■ 新・ゲーム開発講座




■ へっぽこプログラミング入門♪


■第56夜:システムメニューON/OFF

今回は、システムメニューをスクリプト側からON/OFFできる機能を追加します。と言っても、フラグ1個追加して判定するだけなので超簡単♪(^0^)ソースはこちらです。

システムメニューをON/OFFできるようにする目的は、ずばりSAVE/LOADの抑制です。SAVE機能を作成したところでも書きましたが、本稿のプログラム(…そういえば名前がまだ無いなぁ ^^;)はSAVE/LOADにおいては画面のケアを行いません。その画面に読み込んだ最新の画像ファイル名のみキャッシュしておいてLOAD時にはそれを読み込むだけです。よって、なにかのイベント処理で背景に複数の画像を重ね合わせたりしていても、そこでSAVE→LOADすると画面構成が崩れる場合があるのです。これを防ぐためにSAVEポイントという仕掛けを用意したのですが、ここではそれとは別にスクリプター側の意思でシステムメニューを開くことを許可するか禁止するかを選べるようにしようというものです。仕様は、次のように致しましょう。デフォルトはシステムメニュー許可(フラグ=ON)とします。

書式: #system_menu_flag flag

flag : ON = システムメニューを開くことを許可
OFF = システムメニュー禁止(開かない)

※ただし起動時のデフォルトはONとする

■Mode_stat

フラグ構造体に新しいメンバとして flag_system_menu_effective を加えます(ちょっと名前が長かったかな…まあ、いいか ^^;)


//プログラムの制御用FLAG構造体
struct _Mode_stat {
int flag_text; //テキスト表示:ON=進行 OFF=停止
int flag_delay; //遅延処理:ON=遅延あり OFF=遅延なし
int flag_cursor_blink; //カーソル点滅:ON=点滅 OFF=点滅なし
int flag_halt; //終了:ON=終了 OFF=終了ではない
int flag_page2; //改ページ type2:ON=改ページ処理中 OFF=処理中でない
int flag_g_change; //画面切替効果:ON=切替中 OFF=処理はない
int flag_select3; //3択:ON=選択中 OFF=処理はない
char event_flag[EVENT_FLAG_MAX]; //イベントフラグ
_Str256 str[STR_STR_MAX]; //汎用文字列変数
int flag_system_menu_effective; //システムメニュー有効=ON 無効=OFF
int flag_system_menu; //システムメニュー状態:OFF=処理中ではない/その他=各種メニューID
int flag_start_menu; //きそう時メニュー状態:OFF=処理中ではない/その他=各種メニューID
int flag_fps; //FPS表示:ON=表示あり OFF=表示なし
int flag_shake; //画面揺れ効果: ON=揺れている OFF=処理中でない
int flag_fade_out; //フェードアウト処理 ON=処理中 OFF=処理中でない
int flag_fade_in; //フェードイン処理 ON=処理中 OFF=処理中でない
};
extern _Mode_stat Mode_stat;

■コマンド解釈部

いつもの要領で実行関数を追加します。関数の名前は Com_System_menu_flag() とでもしておきましょう。


void Command_call()
{

char com_name[256];
int i=0;
int flag=OFF;

//コメント文対応
if( *(TEXT+1)=='#' || *(TEXT-1)=='#' ){

//#が2回連続したらコメント文なので行末までテキストポインタを飛ばす

while( *TEXT!=0x0d ) TEXT++;
return;

}

TEXT++; //#を飛ばす

//コマンド文字列の切り出し
while( *TEXT>0x20 ){
com_name[i] = *TEXT;
TEXT++;
i++;
}
TEXT--;
com_name[i]=0; //これはNULL文字

//コマンド名の評価 → 処理関数呼び出し
if( strcmp(com_name,"delay" )==0 ){ Com_delay(); flag=ON;} //遅延
if( strcmp(com_name,"wait" )==0 ){ Com_cursor_blink(); flag=ON;} //カーソルブリンク
if( strcmp(com_name,"w" )==0 ){ Com_cursor_blink(); flag=ON;} //カーソルブリンク
if( strcmp(com_name,"halt" )==0 ){ Com_halt(); flag=ON;} //終了
if( strcmp(com_name,"page" )==0 ){ Com_page(); flag=ON;} //改ページ
if( strcmp(com_name,"g_load" )==0 ){ Com_g_load(); flag=ON;} //BMPのLOAD
if( strcmp(com_name,"g_copy" )==0 ){ Com_g_copy(); flag=ON;} //BMPのCOPY
if( strcmp(com_name,"g_change")==0 ){ Com_g_change(); flag=ON;} //画面切替
if( strcmp(com_name,"flag_on" )==0 ){ Com_flag_on(); flag=ON;} //イベントフラグON
if( strcmp(com_name,"flag_off")==0 ){ Com_flag_off(); flag=ON;} //イベントフラグOFF
if( strcmp(com_name,"disp_flag")==0 ){ Com_disp_flag(); flag=ON;} //イベントフラグ表示
if( strcmp(com_name,"if_flag" )==0 ){ Com_if_flag(); flag=ON;} //フラグによる分岐
if( strcmp(com_name,"jump" )==0 ){ Com_jump(); flag=ON;} //ラベルジャンプ
if( strcmp(com_name,"file_change")==0 ){Com_file_change(); flag=ON;} //ファイル間ジャンプ
if( strcmp(com_name,"select3" )==0 ){ Com_select3(); flag=ON;} //3択
if( strcmp(com_name,"play_wav")==0 ){ Com_play_wav(); flag=ON;} //WAV演奏開始
if( strcmp(com_name,"stop_wav")==0 ){ Com_stop_wav(); flag=ON;} //WAV演奏停止
if( strcmp(com_name,"play_midi")==0 ){ Com_play_midi(); flag=ON;} //MIDI演奏開始
if( strcmp(com_name,"stop_midi")==0 ){ Com_stop_midi(); flag=ON;} //MIDI演奏停止
if( strcmp(com_name,"play_mp3")==0 ){ Com_play_mp3(); flag=ON;} //MP3演奏開始
if( strcmp(com_name,"stop_mp3")==0 ){ Com_stop_mp3(); flag=ON;} //MP3演奏停止
if( strcmp(com_name,"set_font_size")==0 ){ Com_set_font_size(); flag=ON;} //フォントサイズ変更
if( strcmp(com_name,"set_text_area")==0 ){ Com_set_text_area(); flag=ON;} //テキストエリア変更
if( strcmp(com_name,"set_text_wait")==0 ){ Com_set_text_wait(); flag=ON;} //テキストウェイト変更
if( strcmp(com_name,"set_text_color")==0 ){ Com_set_text_color(); flag=ON;} //テキストカラー変更
if( strcmp(com_name,"set_str")==0 ){ Com_set_str(); flag=ON;} //文字列変数に値をセット
if( strcmp(com_name,"text_input")==0 ){ Com_text_input(); flag=ON;} //ダイアログを開いてテキスト入力
if( strcmp(com_name,"save_point")==0 ){ Com_save_point(); flag=ON;} //セーブポイント設定
if( strcmp(com_name,"sp")==0 ) { Com_save_point(); flag=ON;} //セーブポイント設定(短縮表記)
if( strcmp(com_name,"save_point_mode")==0 ){Com_save_point_mode(); flag=ON;}//セーブポイントモード
if( strcmp(com_name,"disp_save_point_mode")==0 ){Com_disp_save_point_mode();flag=ON;} //セーブポイントDEBUG用
if( strcmp(com_name,"shake")==0 ) {Com_shake(); flag=ON;} //揺れる効果
if( strcmp(com_name,"fade_out")==0 ) {Com_fade_out(); flag=ON;} //フェードアウト
if( strcmp(com_name,"fade_in")==0 ) {Com_fade_in(); flag=ON;} //フェードイン
if( strcmp(com_name,"alpha_copy")==0 ) {Com_alpha_copy(); flag=ON;} //アルファブレンド
if( strcmp(com_name,"system_menu_flag")==0 ){Com_System_menu_flag(); flag=ON;} //システムメニューON/OFF

// ↑
//そのうちここに他のコマンドも追加していきましょう
// ↓

//フラグを見て、切り出されたコマンド名が有効なコマンドだったかどうか確認する
if( flag == OFF ){

char str[256];

sprintf( str,"警告:無効なコマンド [#%s] が記述されています",com_name);
MessageBox(NULL,str,"Command_call()",MB_OK);

}

}


■初期化

久しぶりにデフォルト値がONのメンバが加わったので、プログラム起動時の初期化関数に明示的な初期化を記述しておきます(main.cpp 参照)。


/----------------------------------
// Mainloop用フラグ類の初期化
//----------------------------------

void init_Mode_stat()
{

Mode_stat.flag_text = ON; //テキスト表示ON
Mode_stat.flag_delay = OFF; //遅延OFF
Mode_stat.flag_cursor_blink = OFF; //カーソル表示OFF

Mode_stat.flag_system_menu_effective =ON; //システムメニュー有効

//OFF は 0 に#defineされているので、ここで明示的に
//初期化しない Mode_stat のメンバ変数はデフォルトで
//OFF扱いになります(VCでは構造体のメンバは0で初期化
//されるので♪)。

}



■Mainloop()

main.cppMainloop() でメニュー処理タスクを回している部分を、フラグがONの場合のみ回るように細工します。


void Mainloop(void)
{

static DWORD fps_keep=0; //FPSを一定に保つためのタイマー変数
if( GetTickCount() < fps_keep + 1000/80 ) return;
fps_keep = GetTickCount(); //システム時刻を取得

//テキスト表示
if( Mode_stat.flag_text == ON ) Text_engine();

//遅延
if( Mode_stat.flag_delay == ON ) Com_delay_task();

//カーソルブリンク
if( Mode_stat.flag_cursor_blink == ON ) Com_cursor_blink_task();

//終了
if( Mode_stat.flag_halt == ON ) Com_halt_task();

//改ページ type2
if( Mode_stat.flag_page2 == ON ) Com_page2_task();

//画面切替え効果
if( Mode_stat.flag_g_change == ON ) Com_g_change_task();

//3択
if( Mode_stat.flag_select3 == ON ) Com_select3_task();

//揺れ効果
if( Mode_stat.flag_shake == ON ) Com_shake_task();

//フェード処理
if( Mode_stat.flag_fade_out == ON) Com_fade_out_task();
if( Mode_stat.flag_fade_in == ON) Com_fade_in_task();

//システムメニュー
if( Mode_stat.flag_system_menu_effective==ON ){
switch( Mode_stat.flag_system_menu ){
case SYSMENU_MAIN: //メインメニューのキースキャン
System_menu_task();
break;

case SYSMENU_EXIT: //EXITメニューのキースキャン
System_exit_task();
break;

case SYSMENU_FPS: //FPSメニューのキースキャン
System_fps_task();
break;

case SYSMENU_SAVE: //SAVEメニューのキースキャン
System_save_task();
break;
case SYSMENU_LOAD: //LOADメニューのキースキャン
System_load_task();
break;
}
}

//FPS
if( Mode_stat.flag_fps == ON ) HLS_stc_FPS(Back_DC);

//Disp_Mouse_info(); //マウス情報(不要ならコメント化しちゃってください)

BitBlt(win_hdc,G_OFFSET_X,G_OFFSET_Y,640,480,Back_DC,0,0,SRCCOPY); //裏画面 → 表画面にコピー

}

■コマンド実行部

ソースファイルのどこに記述しようか迷ったのですが、システムメニューに絡む処理なので SystemMenu_01.cpp に記述することにしました(…処理が分散してくると、記述する場所に微妙に悩みます +▽+)。内容は、パラメータを調べてフラグに値をセットしているだけです。


//------------------------------------------------------------------
// システムメニュー ON/OFF フラグ設定
//
// ゲームの進行状況によっては右クリックでシステムメニューが
// 開くと不都合のある場面もある(オープニングドラマの最中とか)
// ので、メニューの ON/OFF をスクリプト側から制御できるように
// しておく。
//
// ■書式 #system_menu_flag flag
//
// flag : ON=メニューを有効にする OFF=メニュー禁止
//
//------------------------------------------------------------------

int Com_System_menu_flag()
{

char str[256];

TEXT++;
strcpy( str, Kaiseki_TextStr() ); //フラグ文字列の切り出し
while( *TEXT==',' || *TEXT==' ' || *TEXT==0x0a )TEXT++;

if( strcmp(str,"ON" )==0 ){
Mode_stat.flag_system_menu_effective=ON; //有効
}
else
if( strcmp(str,"OFF")==0 ){
Mode_stat.flag_system_menu_effective=OFF; //無効

}
else
{
//無意味なパラメータに対してはデフォルトで ON を設定しておく
Mode_stat.flag_system_menu_effective = ON;
msg( "システムメニューフラグに意味不明なシンボルが\n"
"指定されました。強制的に ON (メニュー有効)と\n"
"して扱います (・ω・)ノシ","Com_System_menu_flag()");
}
return 0;


}


さて、ソースをコンパイルして実行してみてください。ちゃんとメニューのON/OFFが切り替わっていますね。フラグ判定する場所を変えて「ここではシステムメニューは開けない!」なととメッセージを出しても良いかもしれませんが、そのへんのアレンジは必要性を感じたときにまた考えましょう(^^)