著者:宇野 光純
今回は、Windowsアプリケーションとして動く簡単な2Dゲームの開発を紹介します。汎用プログラミング言語の「C++」と、オープンソースのパソコンゲーム開発用ライブラリの「DXライブラリ」を組み合わせることで、時間と労力は必要ですが、Unityなどのゲームエンジンよりも自由度の高いゲーム開発ができます。
シェルスクリプトマガジン Vol.61は以下のリンク先でご購入できます。
図1 DXライブラリを使用する際の基本コード(Main.cpp)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include "DxLib.h" // プログラムはWinMainから開始 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // DXライブラリ初期化処理 if( DxLib_Init() == -1 ) { return -1; // エラーが起きたら直ちに終了 } // ウィンドウモードで起動、拡大して表示する ChangeWindowMode(TRUE); SetWindowSizeExtendRate(1.5); // ちらつきを消すために、描画先を裏画面にする SetDrawScreen(DX_SCREEN_BACK); while (ProcessMessage() == 0 && ScreenFlip() == 0 && ClearDrawScreen() == 0) { // ここにゲームの処理を書く } DxLib_End(); // DXライブラリ使用の終了処理 return 0; // ソフトの終了 } |
図2 「Info.cpp」ファイルに記述するコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include "DxLib.h" #include "Info.h" int g_Width, g_Height; // ウィンドウの横幅と縦幅 int g_StageTime; // ステージ開始からの経過時間 static const int KEY_NUM = 256; // キー配列の最大値 char g_Buf[KEY_NUM]; // キーの状態を保持する配列 void InfoInitialize() { // 各データの初期化 GetScreenState(&g_Width, &g_Height, NULL); g_StageTime = 0; } void InfoUpdate() { // 各データの更新 g_StageTime++; } int GetWidth() { // ウィンドウの横幅を返す return g_Width; } int GetHeight() { // ウィンドウの縦幅を返す return g_Height; } int GetStageTime() { // ステージ開始からの経過時間を得る return g_StageTime; } void KeyUpdate() { // 全キーの状態を更新する GetHitKeyStateAll(g_Buf); } bool GetKey(int key_code) { // 指定したキーの状態を取得する if (g_Buf[key_code]) { return true; } return false; } |
図3 「Info.h」ファイルに記述するコード
1 2 3 4 5 6 7 8 9 |
#pragma once void InfoInitialize(); void InfoUpdate(); int GetWidth(); int GetHeight(); int GetStageTime(); void KeyUpdate(); bool GetKey(int key_input); |
図4 「Object.h」ファイルに記述するコード
1 2 3 4 5 6 7 8 9 |
#pragma once class Object { protected: int size; // 画像サイズ public: double x, y; // X座標、Y座標 virtual void Update() {} // 更新 virtual void Draw() {} // 描画 }; |
図5 「Player.cpp」ファイルに記述するコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#include "DxLib.h" #include "Player.h" #include "Info.h" #include <math.h> int Player::image; Player::Player() { x = y = 200.0; v = 4; // 座標と速度の初期化 SetImage(); // 画像関連の設定 } void Player::Update() { Move(); // 移動の更新 } void Player::Draw() { // 描画 DrawGraph((int)(x - size / 2), (int)(y - size / 2), image, TRUE); } void Player::SetImage() { // 画像関連の設定 size = 64; image = LoadGraph("./images/player.png"); } void Player::Move() { // 自機操作 double nxv = 0, nyv = 0; // 移動量保持用 // X方向の移動量の調整 if (GetKey(KEY_INPUT_LEFT)) { nxv -= v; } if (GetKey(KEY_INPUT_RIGHT)) { nxv += v; } // Y方向の移動量の調整 if (GetKey(KEY_INPUT_UP)) { nyv -= v; } if (GetKey(KEY_INPUT_DOWN)) { nyv += v; } if (GetKey(KEY_INPUT_LSHIFT)) { nxv /= 2; nyv /= 2; } if (nxv != 0 && nyv != 0) { nxv /= sqrt(2); nyv /= sqrt(2); } x += nxv; y += nyv; // 移動量の加算 // 移動範囲外に出たときは範囲内に戻す if (y < 0) { y = 0; } if (GetHeight() < y) { y = GetHeight(); } if (GetWidth() < x) { x = GetWidth(); } if (x < 0) { x = 0; } } |
図6 「Player.h」ファイルに記述するコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#pragma once #include "Object.h" class Player : public Object { private: static int image; // 画像ハンドル void SetImage(); // 画像関連の設定 void Move(); // 自機の操作 public: double v; // 移動速度 Player(); void Update(); // 更新 void Draw(); // 描画 }; |
図7 「Enemy.cpp」ファイルに記述するコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include "DxLib.h" #include "Enemy.h" #include "Info.h" int Enemy::image; Enemy::Enemy() { x = GetWidth() / 2; y = 50.0; // X、Y座標の初期化 xv = yv = 0.0; // 増加量の初期化 this->SetImage(); // 画像関連の設定 } void Enemy::Update() { x += xv; y += yv; } void Enemy::Draw() { DrawGraph((int)(x - size / 2), (int)(y - size / 2), image, TRUE); } void Enemy::SetImage() { size = 64; image = LoadGraph("./images/enemy.png"); } |
図8 「Enemy.h」ファイルに記述するコード
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#pragma once #include "Object.h" class Enemy : public Object { private: static int image; // 画像ハンドル void SetImage(); // 画像関連の設定 public: double xv, yv; // X、Y 方向の増加量 Enemy(); void Update(); // 更新 void Draw(); // 描画 }; |
図9 「MainScene.cpp」ファイルに記述するコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include "DxLib.h" #include "MainScene.h" #include "Info.h" MainScene::MainScene() { // 背景を灰色に SetBackgroundColor(100, 100, 100); InfoInitialize(); // ウィンドウサイズなどの初期化 player = Player(); // 自機の初期化 enemy = Enemy(); // 敵機の初期化 } void MainScene::Update() { InfoUpdate(); // 各データの更新 player.Update(); // 自機の操作 enemy.Update(); // 敵機の更新 } void MainScene::Draw() { player.Draw(); enemy.Draw(); // 自機と敵機の描画 // 経過時間の描画 DrawFormatString(GetWidth() / 2 - 40, 0, GetColor(255, 255, 255), "Time : %d", GetStageTime()); } |
図10 「MainScene.h」ファイルに 記述するコード
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#pragma once #include "Player.h" #include "Enemy.h" class MainScene { private: Player player; Enemy enemy; public: MainScene(); void Update(); // 更新 void Draw(); // 描画 }; |
図11 コードを追加した「Main.cpp」ファイルの内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include "DxLib.h" #include "MainScene.h" #include "Info.h" int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { if( DxLib_Init() == -1 ) { return -1; } ChangeWindowMode(TRUE); SetWindowSizeExtendRate(1.5); SetDrawScreen(DX_SCREEN_BACK); // シーンの初期化 MainScene ms = MainScene(); while (ProcessMessage() == 0 && ScreenFlip() == 0 && ClearDrawScreen() == 0) { KeyUpdate(); // ゲーム終了 if (GetKey(KEY_INPUT_ESCAPE)) { break;} ms.Update(); // 更新 ms.Draw(); // 描画 } DxLib_End(); return 0; } |