DXライブラリとC言語でゲーム作成するその2。今回はcppファイルが肥大化する前に分割する方法について。DXライブラリというよりはVisual Studioでファイルを分割する方法になります。
ソースファイルを分割する意味
キー入力ができるようになったので次は画像や3Dモデルを表示させて動かして…といきたいところだがその前に意識しておきたいのがソースファイルの分割。
現在キー入力のみだけ書いているのでコードは短く済んでいるが、これからシーン管理やプレイヤー、敵、マップ、エフェクト、BGMなどいろんな処理を書いていくことになる。
これらの処理を1つのファイルに全部書き込んでしまうとどこに何の機能があったかわかりにくくなってしまう。グローバル変数関連で思わぬバグを生み出してしまうことも。
ということでとある単位でファイルを分割することを意識しておきたい。今回は試しに前回書いたソースコードからゲームシステム部分・キー入力部分を別のソースファイルに分離してみる。
またソースファイルを分割する際そのままだと他のソースファイルから関数にアクセスできないのでヘッダーファイルもセットで作成する。
ソースファイルの分割の仕方
上のメニューバーから「プロジェクト」→「新しい項目の追加」を選択する。

下の画面が出てきた場合は「すべてのテンプレートの表示」を選択する。

C++ファイル(.cpp)とヘッダーファイル(.h)をそれぞれ選んで名前を入力して「追加」をクリックする。

追加したcppファイルに他のcppファイルのコードを移動させたり続きを書く。また他のcppファイルからアクセスできるようにhファイルにはcppファイルに書いた関数を宣言する。
サンプルコード
前回のコードからキー入力の部分を別のcpp/hファイルに移動し、またシステムの根幹になる部分も別のcpp/hファイルに移動させてみる。
その結果System.cpp、System.h、Input.cpp、Input.hの4つを追加した。
前回のメインファイル Main.cpp は以下になった。
#include <Windows.h>
#include "System.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//ゲームシステムのメイン関数を呼ぶ
System_Main();
return 0;
}
ゲームシステムのメイン関数を呼ぶだけのシンプルなものに。これぐらいならSystem.cpp/hに統合してもいいような気がするがDXライブラリ置き場のサンプルゲームのコードをはじめこう書いているサイトが多いので右に倣えということで。
System.cppは以下の通り。
#include "DxLib.h"
#include "System.h"
#include "Input.h"
//DXライブラリなどの初期化
bool System_Intialize() {
// ウィンドウモードに設定
ChangeWindowMode(TRUE);
// DXライブラリ初期化処理
if (DxLib_Init() < 0) {
//エラーなら終了する
return false;
}
//描画先を裏画面にする
SetDrawScreen(DX_SCREEN_BACK);
// 画面モードの変更
SetGraphMode(WINDOWSIZE_X, WINDOWSIZE_Y, COLORBITNUM);
return true;
}
//描画処理
void System_Draw() {
DrawFormatString(0, 0, GetColor(255, 255, 255), "ESCキーで終了します");
}
//終了処理
void System_Finalize() {
DxLib_End(); // DXライブラリ終了処理
}
//メインループ
bool System_MainLoop() {
while (1) {
//裏画面を表画面に反映, メッセージ処理, 画面クリアの3つが正しく動作してるか確認
//どれか1つでも異常があれば強制終了
if (!(ScreenFlip() == 0)) return false;
if (!(ProcessMessage() == 0)) return false;
if (!(ClearDrawScreen() == 0)) return false;
//キーボードの入力状態を更新
Input_UpdateKeyboard();
//テキストなどの描画
System_Draw();
//ESCキーが30フレーム以上押されていれば終了
//押された瞬間で判定する場合は if(Input_GetKeyboardDown())
//離された瞬間で判定する場合は if(Input_GetKeyboardUp()) とする
if (Input_GetKeyboard(KEY_INPUT_ESCAPE) > 30) {
break;
}
}
return true;
}
//ソフトの処理を実行
bool System_Main() {
//初期化 失敗(false)なら終了
if (!System_Intialize()) return false;
//メインループ
if (!System_MainLoop()) return false;
//終了処理
System_Finalize();
//正常終了
return true;
}
System.cpp/hはゲームのメイン処理を行う関数。大事なのはSystem_MainLoop()のwhile文内でここがゲームの中核となる。
また SetGraphMode() で指定する画面サイズやカラービット数は後述するhファイルに定義として宣言している。
System.hは以下の通り。
#ifndef DEF_SYSTEM_H #define DEF_SYSTEM_H #define WINDOWSIZE_X 1280 #define WINDOWSIZE_Y 720 #define COLORBITNUM 32 bool System_Intialize(); bool System_MainLoop(); void System_Draw(); void System_Finalize(); bool System_Main(); #endif
hファイルを追加したとき最初は #program once といった文字があると思う。これは二重インクルードを防ぐものだが環境依存なため使えなくなることがある(特にチームで開発する場合)。そのため #ifdef~#endif を採用した。
#ifdef~#endif 使い方は以下の通り。
#ifndef DEF_(大文字のヘッダファイル名)_H #define DEF_(大文字のヘッダファイル名)_H //ここに関数などを定義する #endif
前回のキー入力部分にあたるInput.cppは以下の通り
#include "DxLib.h"
#include "Input.h"
static int Input_Keyboard[256]; //キーが押されているフレーム数を格納する
//キーボードの入力状態を更新する
void Input_UpdateKeyboard() {
int i;
char tmpKey[256]; //現在のキーボードの入力状態を格納する
// 全てのキーの入力状態を得る
GetHitKeyStateAll(tmpKey);
for (i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Input_Keyboard[i]++; // 加算
}
else { // 押されていなければ
if (Input_Keyboard[i] > 0) { //前フレームで対応するキーが押されていれば
Input_Keyboard[i] = -1; // -1にする。-1はキーが離された時用の値
}
else {
Input_Keyboard[i] = 0; // 0にする
}
}
}
}
//指定のキーが押された瞬間か調べる
bool Input_GetKeyboardDown(int KeyCode) {
if (Input_Keyboard[KeyCode] == 1) return true;
return false;
}
//指定のキーが押されているか調べる。返り値は押されているフレーム数
int Input_GetKeyboard(int KeyCode) {
return Input_Keyboard[KeyCode];
}
//指定のキーが離された瞬間か調べる
bool Input_GetKeyboardUp(int KeyCode) {
if (Input_Keyboard[KeyCode] == -1) return true;
return false;
}
int Input_Keyboard[256]の前に static がついているがこれは別のcppファイルから値を書き変えられないようにするもの。別のcppファイルから値を自由に書き変えられるようにするとバグの原因となるので変数にはできる限りstaticをつけておくこと。
Input.hは以下の通り。
#ifndef DEF_INPUT_H #define DEF_INPUT_H void Input_UpdateKeyboard(); bool Input_GetKeyboardDown(int KeyCode); int Input_GetKeyboard(int KeyCode); bool Input_GetKeyboardUp(int KeyCode); #endif
ちなみに「ファイルを分ける単位」はキー入力やシーン管理、プレイヤー、敵、マップ、エフェクト、BGMといった具合に分けておくといいらしい。特にプレイヤーや敵、エフェクトなどゲーム中同時に複数存在するものは一括で処理できるようにしておくと便利。

コメント