■ 新・ゲーム開発講座




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


■第23夜:画面切替え@

BMPの転送が出来るようになったところで、ノベルによくある画面切替えの簡単なエフェクトをつくってみましょう。単純な転送だけだと味気ないですし、「撃つ」「回す」「締める」タイプのコマンドとして画面切替えは格好の素材です(^^)。とりあえず切り替えエフェクトは3種類ほど作ることにしましょう。今回は、単純に左から右へカーテンのように画像が切り替わるタイプを作ります。ソースはこちらです。

■書式 : #g_change

仕様:背景画面からバックサーフェイスに画面内容を遅延込みで転送する。転送タイプは画面左端→右端にかけてカーテン式に行う。



今回は読み込みパラメータは無しで行きます。

■処理の概要

BG面からバックサーフェイスへ、コマ送りの要領で順次画像データをコピーしていきます。バックサーフェイスがすっかりコピー元のデータで置き換わったら終了します。なお、結果的にバックサーフェイスに展開している文字データを上書きすることになりますので、テキスト表示の立場からは実質的な改ページとなります。そこで終了時には文字表示位置を初期化して戻るようにします。

■フラグ

main.cpp
_Mode_stat のメンバに以下のフラグを追加します。



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=処理中でない
i
nt flag_g_change; //画面切替効果:ON=切替中 OFF=処理はない

};

■コマンド解釈部

定型作業ですね。以下のように処理関数を登録しておきます(TextEngine.cpp)。


void Command_call()
{

//省略

//コマンド名の評価 → 処理関数呼び出し
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;} //画面切替

//省略

}


■撃つ

では、コマンドのファーストショットです。だんだんコマンドも増えてきましたので、サンプルソースを分割して新たに Text_Com_02.cpp として記述してあります。そうそう、別ファイルに分けた場合、ヘッダファイルの作成および他のソースでのインクルードを忘れちゃいけませんよ♪

処理内容としては定型通りです。Mainloop() で処理分けに使用しているフラグを操作して、テキスト表示を停止したうえで切替処理のフラグをONにしています。そして、毎回の画像転送量をカウントする g_chane_frame_counter をリセットし、タイマーを撃ちます。



DWORD g_change_timer; //大麻・・・じゃなくてタイマ
DWORD g_change_wait = 20; //Wait値(1コマあたり)
int g_change_frame_counter; //フレームカウンタ

int Com_g_change()
{

//テキスト表示を停止する
Mode_stat.flag_text = OFF;

//画面切替えのフラグを立てる
Mode_stat.flag_g_change = ON;

//フレームカウンタをゼロクリア
g_change_frame_counter = 0;

//タイマーショット
HLS_timer_start(&g_change_timer);

return 0;


}


■回す/締める

Mainloop() から呼ばれるタスク部分は、以下のように記述します。まず、指定時間経過していなければそのまま処理を戻す関所を設けておきます(ここでウェイトを取っている訳ですね)。指定時間経過した場合は、次回に向けたタイマーショットを放ったうえで、BitBlt()で縦長の矩形領域(1コマ分)を背景画面 → バックサーフェイス に転送してやります。

1回分の転送が終ったら、フレームカウンタを調べて画面全体の転送が終ったかどうかを判定します。ここでは横10ピクセルずつ転送を繰り返していて、カウンタもこの転送ピッチで加算を繰り返しています。これが画面の横サイズ=640に達したかどうかで終了判定が出来る訳ですね。

もし画面転送がすべて完了したら、フラグ類を元に戻したうえで、文字表示位置をリセットしておきます。転送によって表画面の文字は消えてしまいますから、実質的な改ページと一緒の扱いをする訳ですね。



int Com_g_change_task()
{

int pitch = 10;

//タイマーチェック
if( HLS_timer_check( g_change_timer,g_change_wait )==false )return 0;

//タイマーショット
HLS_timer_start(&g_change_timer);

BitBlt( Back_DC,g_change_frame_counter,0,pitch,480,BG_DC,g_change_frame_counter,0,SRCCOPY );

if ( g_change_frame_counter < 640 ) {
g_change_frame_counter += pitch;
} else {

//終了

//テキスト表示を再開する
Mode_stat.flag_text = ON;

//画面切替えのフラグをクリア
Mode_stat.flag_g_change = OFF;

//文字表示位置を初期化しておく
TEXT_X = TEXT_AREA.left;
TEXT_Y = TEXT_AREA.top;

}

return 0;

}

さて、実行してみるとどうあるでしょう? 左から右へ、つつつ・・・と画面が切り替わる様子が見られると思います。スピードに関しては皆さんのお好みで適宜増減調整願います。



ところで、ここでは解説の都合上、タスク部分での矩形転送を単純に1回だけに限ってインプリメントしました。これだけですとちょっと寂しいので、少しお化粧?をしてみましょう。ソースに以下のようなタスク処理がコメント文の形で書いてありますので、こちらを実行してみて下さい。これなら、ちょっとだけ実用になりそうでしょう?(^^) みなさんも、適宜工夫して面白いエフェクトを編み出して下さい。


int Com_g_change_task()
{

int pitch = 10;

//タイマーチェック
if( HLS_timer_check( g_change_timer,g_change_wait )==false )return 0;

//タイマーショット
HLS_timer_start(&g_change_timer);

BitBlt( Back_DC,g_change_frame_counter ,0,pitch-9,480,BG_DC, g_change_frame_counter ,0,SRCCOPY);

BitBlt( Back_DC,g_change_frame_counter -10 ,0,pitch-8,480,BG_DC, g_change_frame_counter -10 ,0,SRCCOPY);

BitBlt( Back_DC,g_change_frame_counter -20 ,0,pitch-7,480,BG_DC, g_change_frame_counter -20 ,0,SRCCOPY);

BitBlt( Back_DC,g_change_frame_counter -30 ,0,pitch-6,480,BG_DC, g_change_frame_counter -30 ,0,SRCCOPY);

BitBlt( Back_DC,g_change_frame_counter -40 ,0,pitch-5 ,480,BG_DC, g_change_frame_counter -40 ,0,SRCCOPY);

BitBlt( Back_DC,g_change_frame_counter -50 ,0,pitch-4 ,480,BG_DC, g_change_frame_counter -50 ,0,SRCCOPY);

BitBlt( Back_DC,g_change_frame_counter -60 ,0,pitch-3 ,480,BG_DC, g_change_frame_counter -60 ,0,SRCCOPY);

BitBlt( Back_DC,g_change_frame_counter -70 ,0,pitch-2 ,480,BG_DC, g_change_frame_counter -70 ,0,SRCCOPY);

BitBlt( Back_DC,g_change_frame_counter -80 ,0,pitch-1 ,480,BG_DC, g_change_frame_counter -80 ,0,SRCCOPY);

BitBlt( Back_DC,g_change_frame_counter -90 ,0,pitch ,480,BG_DC, g_change_frame_counter -90 ,0,SRCCOPY);


if( g_change_frame_counter - 100 < 640 ) {
g_change_frame_counter += pitch;

} else {

//終了条件

//テキスト表示を再開する
Mode_stat.flag_text = ON;

//画面切替えのフラグをクリア
Mode_stat.flag_g_change = OFF;

//文字表示位置を初期化しておく
TEXT_X = TEXT_AREA.left;
TEXT_Y = TEXT_AREA.top;


}

return 0;


}



そんな訳で、今回はここまで♪(^^)



(^0^)