BREW ブロック崩しゲーム 〜 BREW C++ ゲームプログラミング 〜
図形と文字の描画
続いて、図形や文字の描画に関する処理です。
ゲーム中、ラケットやボールはそれぞれの色で描いたり、背景色で塗りつぶしたり (要するに消す) することを何度もしなければならないので、今回は用途別に関数を作りました。
どの関数についても、flag 引数が true の場合は本来の色で描画し、false の場合には背景色で描画します。(デフォルトは flag = true です。)
ブロックを描画する (DrawRectangle)
ブロックの描画を行う DrawBlock 関数は、次のようになっています。
Void Block::DrawBlock(SInt16 n, Bool flag) { if (n < 0) { // 全てのブロックを描画 for (SInt16 i = 0; i < BLOCK_H_NUM * BLOCK_V_NUM; i++) { DrawBlock(i); } return; } if (!flag) { // 消去 _pgraphics->ClearRectangle(_blocks[n].block); } else { if (_blocks[n].type != BLOCK_TYPE_NONE && _blocks[n].type != BLOCK_TYPE_INVISIBLE) { // 描画 _pgraphics->SetFillMode(true); // 図形内塗りつぶし _pgraphics->SetForeColor(SFXRGBColor(255, 255, 255, 0)); // 境界は白線 _pgraphics->SetFillColor(_blocks[n].color); // そのブロックの色 _pgraphics->DrawRectangle(_blocks[n].block); // 実際の描画 } } }
先にブロックを描く処理について説明します。
今回、個々のブロック同士の境界を明確にするために、白い輪郭線を描画し、その内部をそれぞれのブロック固有の色で塗りつぶすことにしました。
その実現方法ですが、まず
_pgraphics->SetFillMode(true);
で塗りつぶしモードを有効にします。
そして輪郭線を
_pgraphics->SetForeColor(SFXRGBColor(255, 255, 255, 0));
で白色に指定し、ブロック内部の色を
_pgraphics->SetFillColor(_blocks[n].color);
で指定します。
最後に
_pgraphics->DrawRectangle(_blocks[n].block);
でブロックを描画します。
つまり、先に色を SetForeColor と SetFillColor で指定しておいて、その後で DrawRectangle を呼び出すのです。ただしこれだけでは画面は更新されないことに注意してください。
一方ブロックの消し方ですが、
_pgraphics->ClearRectangle(_blocks[n].block);
でそのブロックがある場所を背景色で塗りつぶします。
ラケットを描画する (FillRoundRectangle)
ラケットがブロックと同じ普通の長方形では味気ないので、角が丸くなった長方形をラケットに使用してみましょう。(とは言え、ボールとの衝突判定は長方形のままですが…。)
ラケットを描画するコードは次のようになっています。
Void Block::DrawRacket(Bool flag) { if (!flag) { // 消去 _pgraphics->ClearRectangle(_racket.racket); } else { // 描画 _pgraphics->FillRoundRectangle(_racket.racket, SFXSize(RACKET_CORNER, RACKET_CORNER), _racket.color); } }
この中で使用した FillRoundRectangle の定義は次の通りです。
Void FillRoundRectangle( SFXRectangleConstRef rectangle, // 外接する長方形 SFXSizeConstRef size, // 角を構成する楕円の幅と高さ SFXRGBColorConstRef color // 描画色 );
つまり rect が指す長方形の角の部分が size.GetWidth()、高さが size.GetHeight() である楕円に置き換えられて描画されるのです。
この長方形は見かけこそ普通の長方形と異なりますが、長方形にはかわりありません。つまり、ラケットを消すやり方は、ブロックを消すやり方と同じです。
ボールを描画する (FillCircle)
ボールの描き方は、ブロックやラケットの描き方と基本的に同じです。
描きたい円を予め SFXCircle オブジェクトとして準備しておき、それを SFXGraphics クラスの DrawCirlce メンバ関数やFillCircle メンバ関数の引数として与えます。
では、実際のコードを見てみましょう。
Void Block::DrawBall(Bool flag) { if (!flag) { // 消去 SFXRGBColor BGColor = _pgraphics->GetBackColor(); _pgraphics->FillCircle(_usingBall.ball, BGColor); } else { // 描画 _pgraphics->FillCircle(_usingBall.ball, _usingBall.color); } }
先の 2 つ (ブロックとラケットの描画処理) との違いは、ボールの絵を消すところにあります。ClearRectangle に相当する、円を背景色で塗りつぶしてくれるような関数は存在しないので、
SFXRGBColor BGColor = _pgraphics->GetBackColor();
によって背景色を取得しておいて、
_pgraphics->FillCircle(_usingBall.ball, BGColor);
で背景色で内部が塗りつぶされた円を描くことで解決します。
文字の描画
ゲーム中の文字の描画は、1 組のオーバー ロードされた関数
- Void Block::DrawMessage(SFXWideStringConstRef msg)
- Void Block::DrawMessage(Void)
の中で行っています。
DrawMessage(Void) は Block::_score に格納されている現在の得点を一端文字列に変換し、それを引数にして DrawMessage(SFXWideStringConstRef msg)を呼び出しています。
このブロック崩しは、残りのボールの数を画面の右下にアイコンで表示するようになっています。ところが得点など現在の状況を表示する際、つまり文字を描画する際、背景が上書きされてしまうので、アイコンまで消えてしまいます。
ですから、DrawMessage 内では文字描画後にアイコンを再描画する処理も行っているのですが、ここでは文字列描画処理に的を絞って説明します。
まずは整数型から文字列 (より正確には BREW ワイド文字列) への変換の仕方です。と言っても、この方法は整数型からの変換だけに限りません。
SFXWideString クラスには、Format( ACharConstPtr format, ...) という静的メンバ関数が存在します。
この関数は C 言語の printf 関数と同じ要領で format に書式を記述することで、整形されたものを SFXWideString として取得するためのものです。この際、format は ASCII 文字列で構いません。(この Format 関数にはオーバー ロードが幾つか存在し、その中には format が BREW ワイド文字列のものもあります。)
このブロック崩しでは、この関数を次のように使用しています。
SFXWideString msg = SFXWideString::Format("Score: %d", _score);
これにより、msg の中に “Score: (得点)” という形で、_score の内容が取り出せます。
整数型のデータが文字列に変換できたところで、今度はその文字列を画面に表示させましょう。使う関数は SFXGraphics::DrawText です。
この関数にはオーバー ロードが幾つもあるので、その中で使用頻度の高そうな 3 つを紹介します。
Void DrawText( SFXWideStringConstRef string, // 描画文字列 SFXGridConstRef grid, // 描画座標 SFXRectangleConstRef rectangle, // 描画範囲の長方形 UInt32 align = IDF_ALIGN_NONE // アラインメント ); Void DrawText( SFXWideStringConstRef string, // 描画文字列 SFXRectangleConstRef rectangle, // 描画範囲の長方形 UInt32 align = IDF_ALIGN_NONE // アラインメント ); Void DrawText( SFXWideStringConstRef string, // 描画文字列 SFXGridConstRef grid, // 描画座標 UInt32 align = IDF_ALIGN_NONE // アラインメント );
このゲームで使う、_messageArea に文字列 msg を表示するコードは次のようになります。
_pgraphics->SetFont(AEE_FONT_NORMAL); _pgraphics->SetForeColor(MESSAGE_COLOR); _pgraphics->DrawText(msg, _messageArea, IDF_ALIGN_CENTER | IDF_ALIGN_MIDDLE | IDF_RECT_FILL);
ポイントは、DrawText 関数を呼び出す前にフォントとその色を指定しておくことです。因みに上で指定しているアラインメントは次の意味です。
アラインメント | 意味 |
---|---|
IDF_ALIGN_CENTER | _messageArea の左右中央 |
IDF_ALIGN_MIDDLE | _messageArea の上下中央 |
IDF_RECT_FILL | _messageArea を背景色で塗りつぶす |
画面の更新
今まで図形を描き、文字を書いて来ましたが、このままでは画面には表示されません。変更を画面に表示するために、
_pgraphics->Update();
を実行しましょう。
今回のゲームでは、1 つの図形が描画されるたびに Update 関数を呼び出すのは好ましくないので、Void Block::CreateStage(SInt16 n) とVoid Animate(VoidPtr pData) の中でまとめて更新するようにしています。