さて、この項目からようやく基盤のソースの詳しい説明に入ります。基本的にその関数が持っている機能を紹介するのであって、他の関数との連携についてはあまりふれません。そんなことしてると説明が延々となってしまうので。そのため、ここからの.cppシリーズは1つ1つをきっちり理解しながら読み進めるより、2~3回流し読みしたほうが理解しやすいと思います。
ソースファイルの上から順に読み進めいていきます。
#define _GLOBAL_SET_について
#define _GLOBAL_SET_
これですね。これは、global.hでグローバル変数の本体の宣言を行うための定義です。詳しくは別の項で。
メイン関数について
#include"main.h" // メイン関数 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){ ChangeWindowMode(TRUE); // ウィンドウモードで起動 if(DxLib_Init()==-1) // DXライブラリを初期化 return 1; // 初期化に失敗したら終了する // WaitKey(); SetDrawScreen(DX_SCREEN_BACK); // 描画先を裏画面にする FirstInit(); // ゲームを起動したときに1度だけ実行する初期化 MainLoop(); // メインループ InitGraph(); // 読み込んだ画像データを削除する InitSoundMem(); // 読み込んだ音声データを削除する DxLib_End(); // DXライブラリの使用を終了する return 0; // プログラムを終了する }
DXライブラリの初期化をする前にウィンドウモードに変更しています。その後、描画先を裏画面にしています。で、ゲームを起動したときに1度だけ実行する初期化をしています。関数の中身は別のとこで。で、メインループをもった関数の処理に入ります。この関数の中に無限ループがあり、次にメイン関数に戻ってくるのはゲームを終了するときです。で、戻ってきたら読み込んだ画像、音声データをメモリから解放したあとDXライブラリの使用を終了する関数を呼び出し、プログラムを終了します。
アルゴリズムの解説とか一切ねーから!
アルゴリズムの解説とか一切ねーから!
MainLoop関数について
// メインループ関数 void MainLoop(){ // 無限ループ while(1){ // メッセージ処理に異常があった場合またはESCAPEキーが押されたらループを抜ける if( ProcessMessage() != 0 || CheckHitKey( KEY_INPUT_ESCAPE ) != 0 ) break; ClearDrawScreen(); // 裏画面を初期化する GetKeyInput( Key ); // キーボードの押下状況を調べる // ゲームステートによって処理する関数を選択する switch(GameState){ case GS_TITLE: Title.Process(); break; case GS_MAIN: GameMain.Process(); break; case GS_CLEAR: GameClear.Process(); break; case GS_OVER: GameOver.Process(); break; } BgmControl.Process(); // BGMの管理 SeControl.Process(); // 効果音の管理 FpsControl.Process(); ScreenFlip(); // 裏画面を反映する } }
ゲームのメイン処理をする無限ループです。ループ直後にこのループを抜ける条件があります。ESCAPEキーを押すか、何かしらのエラーが発生したらこのループを抜け、ゲームを終了します。
その後、裏画面の初期化を行っています。初期化をしないで次の描画を行うと、前の画面の上に継ぎ足して描画することになります。「画面全体を無地の画像で埋めてしまえば前の画面を消さなくてもいいのでは?」と思ったこともあるのですが、内部的に呼び出さないと動作が不安定になるらしいです。おとなしく呼び出しましょう。
で、自作のキーボードの押下時間を調べる関数を呼び出しています。引数にしたint型の配列にそれが格納されます。
次に、GameStateの値に応じて呼び出す関数を変えています。GameStateはint型のグローバル変数で、現在のゲームの状態を記憶する役割を持ちます。値はdefineマクロを用いて、英字を割り振っています。define.hに書いてあります。たとえば、現在がタイトル画面ならGameStateにGT_TITLEの値を持たせているわけです。このようにすることでタイトル画面の処理とゲームの処理を間違って同時に行うことがないようにしています。タイトルとゲームオーバー画面の処理を同時に行う状況なんて無いわけです。このように、1つの変数の値に対して、割り振られる状況がただ1つに定まるときのswitch文は使い勝手がいいです。
BGM、効果音、ゲームの実行速度の管理はタイトル、ゲーム、クリア画面でも全て同様に行われますから、switch文の外側に書いてあります。これならswitchでどのように分岐してもこれらの関数が実行されます。それぞれの関数についてはそれぞれの項目で。
最後に裏画面を反映しています。
アルゴリズムの解説必要なとことかほとんどねーから!
その後、裏画面の初期化を行っています。初期化をしないで次の描画を行うと、前の画面の上に継ぎ足して描画することになります。「画面全体を無地の画像で埋めてしまえば前の画面を消さなくてもいいのでは?」と思ったこともあるのですが、内部的に呼び出さないと動作が不安定になるらしいです。おとなしく呼び出しましょう。
で、自作のキーボードの押下時間を調べる関数を呼び出しています。引数にしたint型の配列にそれが格納されます。
次に、GameStateの値に応じて呼び出す関数を変えています。GameStateはint型のグローバル変数で、現在のゲームの状態を記憶する役割を持ちます。値はdefineマクロを用いて、英字を割り振っています。define.hに書いてあります。たとえば、現在がタイトル画面ならGameStateにGT_TITLEの値を持たせているわけです。このようにすることでタイトル画面の処理とゲームの処理を間違って同時に行うことがないようにしています。タイトルとゲームオーバー画面の処理を同時に行う状況なんて無いわけです。このように、1つの変数の値に対して、割り振られる状況がただ1つに定まるときのswitch文は使い勝手がいいです。
BGM、効果音、ゲームの実行速度の管理はタイトル、ゲーム、クリア画面でも全て同様に行われますから、switch文の外側に書いてあります。これならswitchでどのように分岐してもこれらの関数が実行されます。それぞれの関数についてはそれぞれの項目で。
最後に裏画面を反映しています。
アルゴリズムの解説必要なとことかほとんどねーから!
FirstInit関数について
// ゲームを起動したときに一度だけ実行する初期化 void FirstInit(){ // 変数の初期化 Title.FirstInit(); GameMain.FirstInit(); GameClear.FirstInit(); GameOver.FirstInit(); BgmControl.FirstInit(); SeControl.FirstInit(); FpsControl.FirstInit(); LoadFiles(); // 画像、音声データなどを読み込む FpsControl.PreCount = GetNowCount(); ChangeGameState( GS_TITLE ); // 最初のゲーム状態をタイトルにセット }
まず、それぞれのFirstInit関数を呼び出します。基盤の場合、全ての変数を0で初期化しているだけです。多くの初期化は開始直前に行うので、この関数にはゲーム作成が進行していってもあまり書き足すことがないかもしれません。
その後、外部ファイルをロードしています。関数の中身は別のところで。
その後、ゲームの実行速度を管理するための変数に現在の時間を格納しています。「FpsControl.FirstInit関数に書けばいいのでは?」しかし、この変数が持つ性質上、変数に値を入れた後に時間のかかるLoadFiles関数を呼び出すのはためらわれます。詳しくは別の項で。
最後に、最初のゲームの状態をタイトルにセットしています。「GameStateに直接GS_TITLEを代入すればいいのでは?」そういうわけにも行きません。詳しくは別の項で。
まったくアルゴリズムの解説とかねーから!
その後、外部ファイルをロードしています。関数の中身は別のところで。
その後、ゲームの実行速度を管理するための変数に現在の時間を格納しています。「FpsControl.FirstInit関数に書けばいいのでは?」しかし、この変数が持つ性質上、変数に値を入れた後に時間のかかるLoadFiles関数を呼び出すのはためらわれます。詳しくは別の項で。
最後に、最初のゲームの状態をタイトルにセットしています。「GameStateに直接GS_TITLEを代入すればいいのでは?」そういうわけにも行きません。詳しくは別の項で。
まったくアルゴリズムの解説とかねーから!
ちなみに、これがオブジェクト指向チックなプログラムソースです。それぞれの関数はほぼ単一の役割しか持たないというものです。ソースファイルが読みやすいですね。ここ読んだだけじゃ何が起こってるのかわからないんですけど。
字下げの位置がばらばらなのは編集が面倒くさいからです。「Visual C++」ではきれいに並んでるんですけど、コピペでこっちに持ってくるとずれます。誰か直しておいてくださs(ry。コメントアウトがあったり無かったりするのは気分です。すいません。
ここまで説明が少ないのはこのソースファイルだけだと思います。このシートは他の関数を呼び出すための関数ばっかりですからw