著者:宇野 光純
今回は、Windowsアプリケーションとして動く簡単な2Dゲームの開発を紹介します。汎用プログラミング言語の「C++」と、オープンソースのパソコンゲーム開発用ライブラリの「DXライブラリ」を組み合わせることで、時間と労力は必要ですが、Unityなどのゲームエンジンよりも自由度の高いゲーム開発ができます。
シェルスクリプトマガジン Vol.61は以下のリンク先でご購入できます。![]()
![]()
図1 DXライブラリを使用する際の基本コード(Main.cpp)
#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」ファイルに記述するコード
#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」ファイルに記述するコード
#pragma once
void InfoInitialize();
void InfoUpdate();
int GetWidth();
int GetHeight();
int GetStageTime();
void KeyUpdate();
bool GetKey(int key_input);
図4 「Object.h」ファイルに記述するコード
#pragma once
class Object {
protected:
int size; // 画像サイズ
public:
double x, y; // X座標、Y座標
virtual void Update() {} // 更新
virtual void Draw() {} // 描画
};
図5 「Player.cpp」ファイルに記述するコード
#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」ファイルに記述するコード
#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」ファイルに記述するコード
#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」ファイルに記述するコード
#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」ファイルに記述するコード
#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」ファイルに 記述するコード
#pragma once
#include "Player.h"
#include "Enemy.h"
class MainScene {
private:
Player player;
Enemy enemy;
public:
MainScene();
void Update(); // 更新
void Draw(); // 描画
};
図11 コードを追加した「Main.cpp」ファイルの内容
#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;
}