今回は自機をつくるとともにゲームとして完成させます。

自機をつくる

自機は円が繋がってできた蛇のような形をしていますが、敵を倒すたびに身体の長さがひとつずつ伸びていきます。そして自身の先頭だけでなく後ろに繋がっている「節」もいっしょに移動させなければなりません。

では自身の後ろに繋がっている節の座標をどのようにして移動させ描画するかですが、自身が移動した座標をリストにして保存していくことにします。このなかを探せば節の座標を求めることができます。

ではJikiクラスのコンストラクタを示します。コンストラクタでは引数の座標をCenterプロパティに格納しています。

自機の初期化

自機の移動

自機の移動関連のメソッドを示します。

自機の描画

描画関連のメソッドを示します。描画するときと当たり判定をするときは先頭部分の中心座標だけでなく、後ろに繋がっている節の座標も取得しなければなりません。

そのときに必要なのが自機の軌跡です。これをフィールド変数 Trajectoryに保存します。ゲーム開始時の自機の位置と長さは決まっているのでInitメソッドで初期化します。

Trajectoryに自機の現在座標を追加する処理を示します。

前回格納した座標(この処理では先頭の要素)と同じ場合(=止まっている状態)はなにもしません。それ以外のときは現在座標をリストの先頭に追加します。

自機の節の中心座標のリストを取得する処理を示します。自機の速度はSpeedであり、TrajectoryにはX座標またはY座標がSpeedずつズレた値が格納されています。それでTrajectoryの要素を(節の直径 / Speed)で刻んでいけば各節の座標を取得することができます。

自機を描画する処理を示します。先頭部分の中心座標と各節の中心座標を求めて円を描画します。

当たり判定

当たり判定の処理を示します。

自分自身を噛んでいないか?

まず自分自身を噛んでしまうとミスです。CheckBiteSelfメソッドは先頭部分の中心座標と先頭部分以外の各中心座標の距離が節の半径よりも接近していないかを調べます。もし節の半径よりも接近している節が見つかった場合は自分自身を噛んでいます。その場合はPlayerDeadイベントを発生させます。イベントハンドラの引数のPlayerDeadArgsには噛んでしまった節の中心座標が入ります。

敵との接触

敵が自機の先頭部分以外の節に接触した場合もミスです。そこでEnemyクラスに当たり判定の処理とPlayerDeadイベントを追加します。

まず敵と自機の先頭部分が接触していないか調べます。この場合は敵を倒したことになるので敵を倒したイベント HitEnemyを発生させます。

ゲームとして完成させる

最後にゲームとして完成させます。Form1クラスのコンストラクタを示します。

フォームの初期化

コンストラクタ内では自機と敵の初期化、イベントハンドラの追加、タイマーの初期化をしています。

自機の移動

CanTurnHorizontallyメソッドとCanTurnVerticallyメソッドはそれぞれ自機が水平方向、垂直方向に移動できるかどうかを調べるためのものです。交差点から5ピクセル以内のズレであれば移動できるものとします。

自機が方向転換できる場合にその方向のキーが押されたら移動方向を変更します。このとき交差点から5ピクセル以内のズレであれば移動できるためズレが発生しています。そのズレはJiki.SetPosXメソッドとJiki.SetPosXメソッドで修正します。

キーが離されたらその方向には移動できないようにします。

Timer.Tickイベントが発生したら移動できる場合は移動させます。また移動の軌跡を追加する必要がある場合はJiki.AddTrajectoryメソッドを呼び出して追加します。そのあと当たり判定とステージクリア判定をおこないます。そのあと敵を移動させてInvalidateメソッドを呼び出します。

描画処理

描画処理をおこないます。

最初にフィールドを描画し、自機、敵の順に描画します。そのあとスコアとゲームオーバーの場合は「GAME OVER」の文字を描画します。

ステージクリア、ゲームオーバーなどの処理

敵を倒したときは加点の処理、ステージクリアのときはその処理をおこないます。

また自機死亡の場合はゲームオーバー処理を行ないます。

ゲームオーバーのあとSキーを押すとRetryGameメソッドが呼び出されゲームが再開されます。その処理を示します。