■ 新・ゲーム開発講座 |
■ へっぽこプログラミング入門♪ |
■第16夜:カーソルブリンク 今回は、カーソルブリンクを実装します。いままでのサンプルはテキストが垂れ流し的に表示されていくだけで、ユーザーがゆっくりと読み終わるまで「待つ」ということが出来ませんでした。やはり適度なところ(たいていの場合は行末や文末)でカーソルをブリンクさせて、ユーザーがキーまたはマウスボタンを押すまで待たせる処理が欲しいところです。そんな訳で、本日もまずはソースをDLして頂いて、それを見ながら進めて参りましょう。
■実装の前に・・・ さて、いきなりですがここでフラグを整理しておきます。このままコマンドをどんどん追加していくと、Mainloop() で参照すべきフラグもどんどん増えていってしまいます。これをグローバル変数で大量に保持するのは管理上もソースの美的観点からも良くありませんので(笑)、構造体にまとめてしまいましょう。とりあえず、ここでは構造体の定義を _Mode_stat という名前にして、いままでのフラグはこのメンバにしてしまいます。そして、これ以降実装するコマンドでは、ここにフラグを付け足していくことに致しましょう。なお構造体の定義は main.h の中で行い、構造体の実態は main.cpp の先頭で Mode_stat という名前で宣言しています。 |
struct _Mode_stat {
}; |
また上記定義内容をみればお気づきのことと思いますが、テキスト表示の進行/停止も独立したフラグで管理するようにします。みな同じベースに立って管理しようということですね。定義が済んだら、初期化も済ませておきましょう。起動時には、テキスト表示を進行するフラグのみが ON で他は OFF にしておきます。フラグの初期化はプログラム起動時に呼ばれる init_game() 内で一緒におこなうようにしておきましょう(main.cpp参照)。 蛇足ですが構造体(変数の型と同義と思って差し支えないでしょう)を定義してその型で変数を宣言すると、メンバの内容はデフォルトで0になります。本ソースでは BasicTips.h において ON=1 OFF=0 に定義していますので、将来メンバ変数が増えた場合、特に明示的に初期化しなくても初期値としてOFFが適用されます。 |
void init_Mode_stat() {
} |
■パーツ用サーフェイス フラグの整理が出来たら、いよいよカーソル表示の下準備です。カーソルブリンクをさせるためには、なによりもまず表示するカーソルの画像が必要ですね。ここでは、25×25ピクセルのパターンを3つ並べて以下のようなBMPを作って使用することにします。
あれ、なんでカーソル3つ分の面積になるんだ?・・・とお思いの方もいるかもしれません(^^)。実は左のパターンがカーソル本体、中央がマスク、右はバッファ用エリアです。マスクとはカーソルを画面に重ねて表示するときに後ろに透けてみえる部分の定義で、図ではマスクの白==RGB(255,255,255) の部分が丁度透けてみえる部分にあたります。 さらに、右側のバッファ領域は、カーソル表示で隠れてしまう部分の背景を一時的に待避するところです。BMP上であらかじめバッファ域を用意してしまうのは手抜きっぽい方法ですが(笑)、いちいちプログラム的に待避領域分のサーフェイスを生成したり消去したり・・・というやり方に比べたら簡便で分かりやすいと思います。 さてBMPが用意できたところで、これを格納するサーフェイス(画面)が必要になります。ここでBMPの保持方法として、@リソースとして保持 A外部ファイルとして読み込む の2種類の選択が可能ですが、今回は外部BMPとして読み込む方法を採用します。将来、カーソル以外のパーツを表示したくなった場合、それをカーソルBMPに書き加えるだけで同じように扱える下地を作っておきたいためです(たとえばADV化したときのウィンドウ枠とか ^^)。 では実装してみましょう。カーソルBMPを保持するサーフェイスを生成するため、まずはグローバル変数としてDCのハンドルとBITMAPのハンドルを宣言します。名前は・・・パーツ置き場ですから Parts なんとかという名前にでもしておきましょうか(安直 ^^;)。 |
|
初期化(main.cpp)については、以前実装したバックサーフェイスと同じ要領です。サーフェイスを作成したら、すかさずBMPを読み込んでおくようにしておきましょう。なお、今回はカーソルBMPに合せて75×25ピクセル分のサーフェイスにしてありますが、将来もっと大きなBMPを読ませたい場合は、その面積に応じて CreateCompatibleBitmap() の引数を変更して下さい。 |
void init_Parts_Surface()
} //---------------------------------- // 初期化メイン //---------------------------------- void init_game()
} |
さて、これでプログラムが起動するのと同時にパーツ用サーフェイスにカーソル画像がロードされるという状況が出来上がりました。ひととおり準備ができたところで、次はいよいよコマンド本体のインプリメントです。 ■撃つ まずは、カーソルブリンクの仕様を確認しておきましょう。
#w という短縮表記を許容したのは、単にスクリプト記述の効率をアップしたいというだけの理由です(笑)。ではさっそくコマンド解釈部 (TextEnine.cpp) に追加しましょう。 |
void Command_call () {
} |
Com_cursor_blink() というのが、コマンド実行部のうち「撃つ」部分に相当する関数です(Text_Com_01.cpp参照)。一種の遅延処理に相当しますのでタイマー変数として cursor_timer というものを用意しました。 処理はまずフラグ操作からです。テキスト表示フラグ Mode_stat.flag_text を OFF にして、カーソルブリンク用のフラグ Mode_stat.flag_cursor_blink を ON にしています。Mainloop() ではこのフラグを参照して、テキスト表示を止めた状態でカーソルブリンクのタスク処理部を連続コールするようになります。 次に、これから行うカーソル表示で上書きされてしまう部分の画像をバッファ領域に待避し、タイマーを撃ちます。最後に1発目のカーソル表示を行って「撃つ」部分の処理はおしまいです。 |
DWORD cursor_timer; //タイマー用変数 int Com_cursor_blink()
} ※テキスト表示位置はグローバル変数 TEXT_X、TEXT_Y で保持されています。カーソル表示位置はこの文字座標に準拠しています。 |
ところで、カーソル表示で2回 BitBlt() を呼んでいますが、これは最初の方がマスク処理、後の方がパターン本体の転送に相当します。これは「くりぬき表示」を行う場合の古典的手法で、論理演算の AND と OR を用いたものです。BitBlt() の転送オプションでは AND が SRCAND、OR が SRCPAINT のシンボル名で定義されています。ここでは詳細は省きますが「マスクを AND して本体を OR するとくりぬき表示が出来る」と覚えておくと便利でしょう。(DirectX ではマスクの代わりにカラーキーを適用できます) |
|
■回す 次に Mainloop() からぐるぐる呼ばれ続けるタスク処理部分です。リストを見れば分かると思いますが、遅延処理の変形版になっています。関数の最初でタイマーチェックを行い、指定時間に達していなければ何もしないでリターンしています。単純な遅延と異なるのは、指定時間に達した後にまた次のタイマーショットを放っていることですね。要は、カーソル表示の ON・OFF を切り替えてはタイマー監視を繰り返しているのです。 |
int Com_cursor_blink_task () {
} |
■締める さて、カーソルブリンクの終了条件ですが・・・マウスの左クリック、またはリターンキー/スペースキーが押された場合でした。これは、イベントハンドラ WndProc() の中でチェックします。おお、いよいよイベントハンドラに手を出すときが来ましたね(^^)。とりあえず下のリストを見て下さい。 キーの押下げもマウスボタンクリックも、それに相当するメッセージコードが定義されています。まずはキー入力ですが、メッセージコードは WM_KEYDOWN、押されたキーの内容は wprm に入ってWindowsのシステムから降ってきます。キーコードは VK_なんたら というシンボル名で定義されています。スペースは VK_SPACE、リターンは VK_RETURN、ついでに ESCは VK_ESCAPE になります。ここでは VK_SPASE と VK_RETURN が押されたの場合のみ、カーソルブリンク終了関数 Com_cursor_blink_end() を呼ぶようにすれば良いのですね。(ついでと言ってはナニですが、ESCキーでプログラムが終了するようにもしてみました ^^;) またマウスの左ボタン押下げは、WM_LBUTTONDOWN です。ここでもまったく同様にカーソルブリンクの終了関数を呼んでいます。 |
LRESULT WndProc(HWND hwnd,UINT msg,WPARAM
wprm,LPARAM lprm) {
|
ではカーソルブリンクの終了はどのようにするのでしょうか。フラグを初期状態に戻してカーソルの背景部分を描き戻せば完了です。簡単ですね♪(Text_Com_01.cpp参照) |
int Com_cursor_blink_end() {
|
さあ、これでずいぶんノベルらしくなってきましたね♪ まだまだ、へっぽこ的に頑張りましょう(^0^) |