■ 新・ゲーム開発講座




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


■第19夜:改ページA

さて、実は今回も改ページについてです。「え〜〜、前回やったじゃない」という声が聞こえてきそうですが、今回は改ページコマンドとしての実装ではありません。#page コマンドに遭遇しないままテキスト表示が画面下端まで行ってしまった場合の対応です。一種の禁則処理ですね。

さっそくですが仕様です。

■書式:なし(文字位置インクリメント処理の中に追加します)

画面下端に達したところでカーソルをブリンクさせてキー入力待ちを行い、マウス左ボタン/スペースキー/リターンキーのいずれかが押されたら、バックサーフェイスを背景画像で書き換える。



・・・なんだか面倒そうな動作ですが、いままでインプリメントしてきた各種コマンドの要素を合体させれば実現できそうです。実際、トリガの位置が異なるだけで他はいままでのコマンド実装と同じ要領で実装できてしまいます。ソースはこちらになります。

■処理の概要

カーソルブリンクの応用になります。改行処理でテキストエリアをはみ出すときにカーソルブリンクと同等のタスクを回し、キー入力(マウスクリック)を検出したら改ページ@(前回)相当の処理を行います。

■フラグ

改ページ type2 ということで、以下のようなフラグ(・・・そのまんまやんけ ^^)を追加します。


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=処理中でない

};

■トリガ

文字位置をインクリメントしている TextEngine.cppIncrement_textp_pos() をトリガとして使います。 いままでの処理部分の前に、現在表示している文字位置が「最終行であって、なおかつ右端−2文字目」の場合のチェックを入れます。

あれれ、TEXT_X_PITCH*4 て何だ?・・・という方、鋭いです(^^;) 注意深くこのシリーズを読んできた方なら気がついているかもしれませんが、ここでいう TEXT_X_PITCH というのは半角英数字の幅なので、TEXT_AREA.right から TEXT_X_PITCH*4 戻った位置というのは全角文字2つ分ということになります。え〜っ、それじゃ半角文字が丁度ページ末に来たら1〜2文字分ずれてしまうじゃないか〜、という声が聞こえそうですが、まあ英文でノベルを書かない限りほとんどの場合は日本語の文章を表示する訳で、ここでは敢えて目をつむりましょう(爆)。どうしても、という方はそんなに難しい処理ではないので各自工夫してみてください♪(たまにはそのくらいの宿題は出さないと・・・ ^^)



void Increment_textp_pos(int inc)
//文字表示位置のインクリメント
// int inc:何byteインクリメントするか→1or2

{

//最終行であって、なおかつ右端−2文字目(カーソルブリンク位置を確保 ^^)
//の場合は「改ページ」扱いにしてしまう。

if( (TEXT_Y+TEXT_Y_PITCH)>=(TEXT_AREA.bottom-TEXT_Y_PITCH) &&
(TEXT_X+TEXT_X_PITCH*inc)>=(TEXT_AREA.right-TEXT_X_PITCH*4) ) {

//カーソル位置が文字座標を参照しているのでとりあえずインクリメント
TEXT_X += TEXT_X_PITCH*inc;

Com_page2(); //改ページ type2
return;

}

if( (TEXT_X+TEXT_X_PITCH*inc) < (TEXT_AREA.right-TEXT_X_PITCH*2) ) {
//行端に達していない場合は単純にX座標を1文字分増やすだけ
TEXT_X += TEXT_X_PITCH*inc;

}else{
//行端では改行処理
TEXT_X = TEXT_AREA.left;
TEXT_Y += TEXT_Y_PITCH;

}



■撃つ

それでは、処理のファーストショットです。以前に実装したカーソルブリンク(第16夜)と同じです。省資源?のためにここではタイマー変数を間借りしていますが(=同時に2つブリンクすることは無い)、将来的にバグの混入を防ぎたいなら専用のタイマー変数を用意しても良いでしょう。

int Com_page2()
{

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

//改ページ用フラグを立てる
Mode_stat.flag_page2 = ON;

//カーソルによって隠れる背景領域を待避しておく
BitBlt(Parts_DC,50,0,25,25,Back_DC,TEXT_X,TEXT_Y,SRCCOPY);

//タイマーショット
HLS_timer_start( &cursor_timer ); //カーソルブリンクのタイマー変数を拝借(^^)

//1発目のカーソル表示
BitBlt(Back_DC,TEXT_X,TEXT_Y,25,25,Parts_DC,25,0,SRCAND ); //AND
BitBlt(Back_DC,TEXT_X,TEXT_Y,25,25,Parts_DC, 0,0,SRCPAINT); //OR

return 0;


}

■回す

これもカーソルブリンク(第16夜)と同じ要領ですね。

int Com_page2_task()
{

static int flag=OFF;

//指定時間経過したか? → していなければ Mainloop に戻る
if( HLS_timer_check( cursor_timer, cursor_wait )==false )return 0;

HLS_timer_start( &cursor_timer ); //次回に向けてのタイマーショット

switch( flag ) {
case ON: //カーソル表示
BitBlt(Back_DC,TEXT_X,TEXT_Y,25,25,Parts_DC,25,0,SRCAND ); //AND
BitBlt(Back_DC,TEXT_X,TEXT_Y,25,25,Parts_DC, 0,0,SRCPAINT); //OR
flag = OFF; //次回はOFF
break;
case OFF: //カーソル非表示
BitBlt(Back_DC,TEXT_X,TEXT_Y,25,25,Parts_DC,50,0,SRCCOPY); //背景書き戻し
flag = ON; //次回はON
break;
}

return 0;

}


■締める

単純なカーソルブリンクと違うのは、最後の締めが「改ページ」(第18夜相当)になっていることです。前回の処理が分かっていれば、特に解説は不要だと思います。(…単に BitBlt() 一発ですし:笑)

int Com_page2_end()
{

//テキスト表示フラグを戻す
Mode_stat.flag_text = ON;

//改ページ用フラグを解除
Mode_stat.flag_page2 = OFF;

//背景データでバックサーフェイスを書き換える
BitBlt(Back_DC,0,0,640,480,BG_DC,0,0,SRCCOPY);

//文字表示位置をテキストエリアの左肩にリセットする
TEXT_X = TEXT_AREA.left;
TEXT_Y = TEXT_AREA.top;

return 0;


}

さて、サンプルソースをコンパイル→実行してみて感じが掴めたでしょうか? 今回は過去のコードのコピー&ペーストで済んでしまうような内容でした(笑)。こーゆー基礎的な部分は「似て異なる処理」が多くて閉口することもありますが、最低限の処理はインプリメントしておきましょう。それはともかく、ここまでくると制御文字として禁則している「#」や「;」、半角カナを含まない文章なら、特にスクリプトコマンドを埋め込まなくても普通にページ単位で表示できるようになります。だんだん汎用性が出てきましたね。