RGKT-NDS-STDY-022(006)
『ゲームプログラマになる前に覚えておきたい技術』を自分なりに解釈して
「Chapter5 かんたんなシーケンス遷移」の言う
階層構造のシーケンス遷移を実装してみました。
CAVE GAME で組んだシーケンス遷移よりももう少しだけちゃんと書き直しました。
一般的な
タイトル<−>ゲーム
のシーン遷移を行っていて、ゲームシーンは更に
メイン、コンフィグへと分岐・シーン遷移します。
初歩の初歩として必要な項目はこのくらいかと。
後はシーンに応じて階層を深く掘って行けばいいんじゃないかと思います。
解釈が間違ってるよーとか、突っ込み大歓迎です。
分かりやすく見れるよう勤めたつもりですが…
書き終わったばっかりで客観視できませんw
後、C++ での説明を独自解釈で C ソースに落とし込んでるので
これで合ってるのか(=理解出来てるのか)が不安だったり(苦笑)。
C++ じゃなくて Cコード の場合の実装参考例として。
C++ でしたら上記書物の付属CDにそのものが入ってるので、
そっちで知ることをお勧めします。
Cソース 5ファイル、ヘッダ 5ファイルの構成です。
メイン関数用と、シーン毎でファイルを分割してこの数になります。
シーン毎にファイル分けするのは1シーン毎の見易さを得るためです。
本当に少しの処理だけなら1ファイルにまとめても構わないと思いますが
関連するシーンが3シーン以上に分岐しそうならファイル分けした方が良いと感じました。個人的に。
後はシーン遷移の、各々の関連性(遷移する流れ・順番等)は結局のところ
コーディングする自分自身が管理・理解してないと
状態遷移を組んでもどう遷移するか見えなくなるので
(このソース場合の遷移は、状態をスタックするタイプじゃなく、
やってるそれはラベルジャンプ(goto)のようなものなので)
小規模以上の遷移を組むなら紙なりテキストファイルなりで
遷移の順は把握できるようにして置いた方が無難です。
続きを読むにて、ソース・ヘッダの内容を見ることができます。
main.h
// TODO: ここに一意の識別子を定義する(重複インクルード防止用)。 #ifndef _MAIN_H_ #define _MAIN_H_ // TODO: ここに、このヘッダファイルが必要とする外部ヘッダファイルを記述する。 #ifdef __cplusplus extern "C" { #endif // TODO: ここに #define 定義、ならびに関数のプロトタイプ宣言を追加する。 //メインループ内、シーン定数 typedef enum{ SCENE_TITLE = 0, SCENE_GAME = 1 }SCENE_SEQ; #ifdef __cplusplus } #endif #endif
main.c
//root //--------------------------------------------------------------------------------- //メインループ内、インクルードヘッダ群 #include <nds.h> #include <stdio.h> #include "main.h" #include "title.h" #include "game.h" //--------------------------------------------------------------------------------- //メインループ内関数、プロトタイプ宣言 void initMain(void); //--------------------------------------------------------------------------------- //メインループ内関数 void initMain(void) { //コンソール初期化 consoleDemoInit(); } //--------------------------------------------------------------------------------- int main(void) { //メインループ内、シーン遷移フラグ SCENE_SEQ scene_seq = SCENE_TITLE; //メイン初期化処理 initMain(); //メインループ while(1) { scanKeys(); //シーケンス遷移 switch(scene_seq){ case SCENE_TITLE: scene_seq = updateTitle(); break; case SCENE_GAME: scene_seq = updateGame(); break; default: break; } swiWaitForVBlank(); } return 0; } //---------------------------------------------------------------------------------
title.h
// TODO: ここに一意の識別子を定義する(重複インクルード防止用)。 #ifndef _TITLE_H_ #define _TITLE_H_ // TODO: ここに、このヘッダファイルが必要とする外部ヘッダファイルを記述する。 #include "main.h" #ifdef __cplusplus extern "C" { #endif // TODO: ここに #define 定義、ならびに関数のプロトタイプ宣言を追加する。 //タイトルシーン更新用、グローバル関数、プロトタイプ宣言 SCENE_SEQ updateTitle(void); #ifdef __cplusplus } #endif #endif
title.c
//SCENE_TITLE //--------------------------------------------------------------------------------- //タイトルシーン用、インクルードヘッダ群 #include <nds.h> #include <stdio.h> #include "title.h" #include "main.h" //--------------------------------------------------------------------------------- //タイトルシーン内、シーン定数 typedef enum{ SCENE_TITLE_INIT = 10, SCENE_TITLE_EXEC = 11, SCENE_TITLE_EXIT = 12 }SCENE_TITLE_SEQ; //--------------------------------------------------------------------------------- //タイトルシーン内、シーン遷移フラグ static SCENE_TITLE_SEQ scene_title_seq = SCENE_TITLE_INIT; //--------------------------------------------------------------------------------- //タイトルシーン内、シーン更新インライン関数、プロトタイプ宣言 static SCENE_TITLE_SEQ initTitle(void);//コントラクタ static SCENE_TITLE_SEQ execTitle(void);//メインループ static SCENE_TITLE_SEQ exitTitle(void);//デストラクタ //--------------------------------------------------------------------------------- //タイトルシーン内、シーン更新インライン関数 static SCENE_TITLE_SEQ initTitle(void) { BG_PALETTE_SUB[0] = RGB15(15, 15, 15); consoleClear(); iprintf("\x1b[7;3HSequence transition sample"); iprintf("\x1b[8;9HScene TITLE"); iprintf("\x1b[11;3HPUSH START to GAME MENU"); return SCENE_TITLE_EXEC; } //--------------------------------------------------------------------------------- static SCENE_TITLE_SEQ execTitle(void) { if(keysDown() & KEY_START){ //スタートボタンが押されたらタイトルシーンを終了する。 return SCENE_TITLE_EXIT; } //タイトルシーンが終わってなければタイトルシーンを継続する。 return SCENE_TITLE_EXEC; } //--------------------------------------------------------------------------------- static SCENE_TITLE_SEQ exitTitle(void) { //デストラクタ処理(次回実行時のために必要な初期化作業) return SCENE_TITLE_INIT; } //--------------------------------------------------------------------------------- //タイトルシーン更新用、グローバル関数 SCENE_SEQ updateTitle(void) { //タイトルシーケンス遷移 switch(scene_title_seq){ case SCENE_TITLE_INIT: scene_title_seq = initTitle(); break; case SCENE_TITLE_EXEC: scene_title_seq = execTitle(); break; case SCENE_TITLE_EXIT: //タイトルシーンを終了。ゲームシーンへ遷移する。 scene_title_seq = exitTitle(); return SCENE_GAME; break; default: break; } return SCENE_TITLE; } //---------------------------------------------------------------------------------
game.h
// TODO: ここに一意の識別子を定義する(重複インクルード防止用)。 #ifndef _GAME_H_ #define _GAME_H_ // TODO: ここに、このヘッダファイルが必要とする外部ヘッダファイルを記述する。 #include "main.h" #ifdef __cplusplus extern "C" { #endif // TODO: ここに #define 定義、ならびに関数のプロトタイプ宣言を追加する。 //ゲームシーケンス内、シーン定数 typedef enum{ SCENE_GAME_INIT = 20, SCENE_GAME_EXEC = 21, SCENE_GAME_MAIN = 22, SCENE_GAME_CONFIG = 23, SCENE_GAME_EXIT = 24 }SCENE_GAME_SEQ; //ゲームシーン更新用、グローバル関数、プロトタイプ宣言 SCENE_SEQ updateGame(void); #ifdef __cplusplus } #endif #endif
game.c
//SCENE_GAME //--------------------------------------------------------------------------------- //ゲームシーン用、インクルードヘッダ群 #include <nds.h> #include <stdio.h> #include "main.h" #include "game.h" #include "gameMain.h" #include "gameConfig.h" //--------------------------------------------------------------------------------- //ゲームシーン内、シーン遷移フラグ static SCENE_GAME_SEQ scene_game_seq = SCENE_GAME_INIT; //--------------------------------------------------------------------------------- //ゲームシーン内、シーン更新インライン関数、プロトタイプ宣言 static SCENE_GAME_SEQ initGame(void);//コントラクタ static SCENE_GAME_SEQ execGame(void);//メインループ static SCENE_GAME_SEQ exitGame(void);//デストラクタ //--------------------------------------------------------------------------------- //ゲームシーン内、シーン更新インライン関数 static SCENE_GAME_SEQ initGame(void) { BG_PALETTE_SUB[0] = RGB15(31, 0, 0); consoleClear(); iprintf("\x1b[7;3HSequence transition sample"); iprintf("\x1b[8;9HScene GAME"); iprintf("\x1b[11;3HPUSH A to GAME MAIN"); iprintf("\x1b[12;3HPUSH B to GAME CONFIG"); return SCENE_GAME_EXEC; } //--------------------------------------------------------------------------------- static SCENE_GAME_SEQ execGame(void) { if(keysDown() & KEY_A){ //Aボタンが押されたらゲームメインシーンへ遷移する。 return SCENE_GAME_MAIN; }else if(keysDown() & KEY_B){ //Bボタンが押されたらゲームコンフィグシーンへ遷移する。 return SCENE_GAME_CONFIG; } //ゲームシーンが終わってなければゲームシーンを継続する。 return SCENE_GAME_EXEC; } //--------------------------------------------------------------------------------- static SCENE_GAME_SEQ exitGame(void) { //デストラクタ処理(次回実行時のために必要な初期化作業) return SCENE_GAME_INIT; } //--------------------------------------------------------------------------------- //ゲームシーン更新用、グローバル関数 SCENE_SEQ updateGame(void) { //ゲームシーケンス遷移 switch(scene_game_seq){ case SCENE_GAME_INIT: scene_game_seq = initGame(); break; case SCENE_GAME_EXEC: scene_game_seq = execGame(); break; case SCENE_GAME_MAIN: scene_game_seq = updateGameMain(); break; case SCENE_GAME_CONFIG: scene_game_seq = updateGameConfig(); break; case SCENE_GAME_EXIT: //ゲームシーン終了。タイトルシーンへ遷移する。 scene_game_seq = exitGame(); return SCENE_TITLE; break; default: break; } return SCENE_GAME; } //---------------------------------------------------------------------------------
gameMain.h
// TODO: ここに一意の識別子を定義する(重複インクルード防止用)。 #ifndef _GAME_MAIN_H_ #define _GAME_MAIN_H_ // TODO: ここに、このヘッダファイルが必要とする外部ヘッダファイルを記述する。 #include "game.h" #ifdef __cplusplus extern "C" { #endif // TODO: ここに #define 定義、ならびに関数のプロトタイプ宣言を追加する。 //ゲームメインシーン更新用、グローバル関数、プロトタイプ宣言 SCENE_GAME_SEQ updateGameMain(void); #ifdef __cplusplus } #endif #endif
gameMain.c
//SCENE_GAME_MAIN //--------------------------------------------------------------------------------- //ゲームメインシーン用、インクルードヘッダ群 #include <nds.h> #include <stdio.h> #include "game.h" #include "gameMain.h" //--------------------------------------------------------------------------------- //ゲームメインシーケンス内、シーン定数 typedef enum{ SCENE_GAME_MAIN_INIT = 220, SCENE_GAME_MAIN_EXEC = 221, SCENE_GAME_MAIN_EXIT = 222 }SCENE_GAME_MAIN_SEQ; //--------------------------------------------------------------------------------- //ゲームメインシーン内、シーン遷移フラグ static SCENE_GAME_MAIN_SEQ scene_game_main_seq = SCENE_GAME_MAIN_INIT; //--------------------------------------------------------------------------------- //ゲームメインシーン内、シーン更新インライン関数、プロトタイプ宣言 static SCENE_GAME_MAIN_SEQ initGameMain(void);//コントラクタ static SCENE_GAME_MAIN_SEQ execGameMain(void);//メインループ static SCENE_GAME_MAIN_SEQ exitGameMain(void);//デストラクタ //--------------------------------------------------------------------------------- //ゲームメインシーン内、シーン更新インライン関数 static SCENE_GAME_MAIN_SEQ initGameMain(void) { BG_PALETTE_SUB[0] = RGB15(0, 31, 0); consoleClear(); iprintf("\x1b[7;3HSequence transition sample"); iprintf("\x1b[8;9HScene GAME MAIN"); iprintf("\x1b[11;1HPUSH START to GAME MAIN END"); iprintf("\x1b[12;1Hnext TITLE"); return SCENE_GAME_MAIN_EXEC; } //--------------------------------------------------------------------------------- static SCENE_GAME_MAIN_SEQ execGameMain(void) { if(keysDown() & KEY_START){ //スタートボタンが押されたらゲームメインシーンを終了する。 return SCENE_GAME_MAIN_EXIT; } //ゲームメインシーンが終わってなければゲームメインシーンを継続する。 return SCENE_GAME_MAIN_EXEC; } //--------------------------------------------------------------------------------- static SCENE_GAME_MAIN_SEQ exitGameMain(void) { //デストラクタ処理(次回実行時のために必要な初期化作業) return SCENE_GAME_MAIN_INIT; } //--------------------------------------------------------------------------------- //ゲームメインシーン更新用、グローバル関数 SCENE_GAME_SEQ updateGameMain(void) { //ゲームメインシーケンス遷移 switch(scene_game_main_seq){ case SCENE_GAME_MAIN_INIT: scene_game_main_seq = initGameMain(); break; case SCENE_GAME_MAIN_EXEC: scene_game_main_seq = execGameMain(); break; case SCENE_GAME_MAIN_EXIT: //ゲームメインシーン終了。ゲームシーン終了へ遷移する。 scene_game_main_seq = exitGameMain(); return SCENE_GAME_EXIT; break; default: break; } return SCENE_GAME_MAIN; } //---------------------------------------------------------------------------------
gameConfig.h
// TODO: ここに一意の識別子を定義する(重複インクルード防止用)。 #ifndef _GAME_CONFIG_H_ #define _GAME_CONFIG_H_ // TODO: ここに、このヘッダファイルが必要とする外部ヘッダファイルを記述する。 #include "game.h" #ifdef __cplusplus extern "C" { #endif // TODO: ここに #define 定義、ならびに関数のプロトタイプ宣言を追加する。 //ゲームコンフィグシーン更新用、グローバル関数、プロトタイプ宣言 SCENE_GAME_SEQ updateGameConfig(void); #ifdef __cplusplus } #endif #endif
gameConfig.c
//SCENE_GAME_CONFIG //--------------------------------------------------------------------------------- //ゲームメインシーン用、インクルードヘッダ群 #include <nds.h> #include <stdio.h> #include "game.h" #include "gameConfig.h" //--------------------------------------------------------------------------------- //ゲームコンフィグシーケンス内、シーン定数 typedef enum{ SCENE_GAME_CONFIG_INIT = 230, SCENE_GAME_CONFIG_EXEC = 231, SCENE_GAME_CONFIG_EXIT = 232 }SCENE_GAME_CONFIG_SEQ; //--------------------------------------------------------------------------------- //ゲームコンフィグシーン内、シーン遷移フラグ static SCENE_GAME_CONFIG_SEQ scene_game_config_seq = SCENE_GAME_CONFIG_INIT; //--------------------------------------------------------------------------------- //ゲームコンフィグシーン内、シーン更新インライン関数、プロトタイプ宣言 static SCENE_GAME_CONFIG_SEQ initGameConfig(void);//コントラクタ static SCENE_GAME_CONFIG_SEQ execGameConfig(void);//メインループ static SCENE_GAME_CONFIG_SEQ exitGameConfig(void);//デストラクタ //--------------------------------------------------------------------------------- //ゲームコンフィグシーン内、シーン更新インライン関数 static SCENE_GAME_CONFIG_SEQ initGameConfig(void) { BG_PALETTE_SUB[0] = RGB15(0, 0, 31); consoleClear(); iprintf("\x1b[7;3HSequence transition sample"); iprintf("\x1b[8;9HScene GAME CONFIG"); iprintf("\x1b[11;1HPUSH START to GAME CONFIG END"); iprintf("\x1b[12;1Hnext GAME MENU"); return SCENE_GAME_CONFIG_EXEC; } //--------------------------------------------------------------------------------- static SCENE_GAME_CONFIG_SEQ execGameConfig(void) { if(keysDown() & KEY_START){ //スタートボタンが押されたらゲームコンフィグシーンを終了する。 return SCENE_GAME_CONFIG_EXIT; } //ゲームコンフィグシーンが終わってなければゲームコンフィグシーンを継続する。 return SCENE_GAME_CONFIG_EXEC; } //--------------------------------------------------------------------------------- static SCENE_GAME_CONFIG_SEQ exitGameConfig(void) { //デストラクタ処理(次回実行時のために必要な初期化作業) return SCENE_GAME_CONFIG_INIT; } //--------------------------------------------------------------------------------- //ゲームコンフィグシーン更新用、グローバル関数 SCENE_GAME_SEQ updateGameConfig(void) { //ゲームコンフィグシーケンス遷移 switch(scene_game_config_seq){ case SCENE_GAME_CONFIG_INIT: scene_game_config_seq = initGameConfig(); break; case SCENE_GAME_CONFIG_EXEC: scene_game_config_seq = execGameConfig(); break; case SCENE_GAME_CONFIG_EXIT: //ゲームコンフィグシーン終了。ゲームシーンへ遷移する。 scene_game_config_seq = exitGameConfig(); return SCENE_GAME_INIT; break; default: break; } return SCENE_GAME_CONFIG; } //---------------------------------------------------------------------------------