Playerクラス ASP.NET Core版 戦車対戦ゲームをつくる(2)
tank-dotnet-player

前回 ASP.NET Core版 戦車対戦ゲームをつくる(1)の続きです。今回はPlayerクラスを定義して戦車を動かすことができるようにします。

ほんとうは以下のように書かなければならないのですが、

以降は省略して

と書きます。

プロパティと初期化

まずコンストラクタとプロパティを示します。

コンストラクタを示します。残機数をMAX_RESTにしてプロパティをセットします。

ゲームが始まったらプレイヤーの戦車をフィールドの端に出現させます。この位置は破壊できない壁の内部で他のプレイヤーからは見えません。戦車の初期座標を決定するのがSetInitPositionメソッドです。

戦車を出現させる座標は一度取得したら同じものを使いまわせるので最初の1回だけ取得してフィールド変数に格納しておきます。あとは戦車の初期の方向をランダムに設定して、それに応じたX座標とZ座標を設定します。

プレイヤーの手前にある壁は非表示に

戦車を描画するときに手前になる壁が存在すると見えないので非表示とします。非表示にさせたいWallオブザーバーのリストを取得するGetWallsToHideメソッドを示します。

方向転換するときに10度刻みで変更されるので315度~45度、45度~135度、135度~225度、225度~315度の4パターンにわけて取得しています。

方向転換と移動

つぎに方向転換と移動の処理を考えます。

方向転換

方向転換するためのRotateメソッドを示します。方向転換するときは_directChangingLまたは_directChangingRに1をセットします。更新処理を行なおうとしたときにこれらのフィールド変数が0以外であれば方向転換をおこなっている最中であることがわかります。また1回の更新処理で10度ずつ回転させるので9回処理をおこなえば方向転換の処理は完了したことになります。

移動処理

Moveメソッドは場所を移動するためのメソッドです。移動処理をおこなうときは_positionChangingに1をセットします。更新処理を行なおうとしたときに戦車の方向に応じてX座標とZ座標を変更し、_positionChangingをインクリメントします。_positionChangingがGame.CHARACTER_SIZEに一致したとき、隣のマスに移動したことになるので移動処理を終了させます。

戦車を前方に移動させることができるかどうかを調べるCanMoveForwardメソッドを示します。

戦車を移動させようとした先に壁が存在する場合は移動させることができません。戦車を移動させようとした先に壁が存在する場合、その座標は戦車の中心座標に戦車のサイズの4分の3または4分の5を加算または減算した値なので、この条件をみたす壁が存在するかどうかを調べています。

戦車はフィールド内に存在するか?

戦車がフィールド内に存在するかどうかを調べるIsOutOfFieldメソッドを示します。戦車をhalfSizeWall分移動させようとすると破壊できない壁と重なってしまうかどうかを調べています。

更新処理がおこなわれるときにキーが押されているかどうかで前進または方向転換処理をおこなうUpdatePlayerメソッドを示します。

LeftKeyまたはRightKeyが押されている場合は方向転換を開始し、UpKeyが押されている場合は前進処理を開始します。すでになんらかの処理がおこなわれている場合はその処理を継続し、それ以外の処理は開始させません。

またフィールドの外にいる場合はフィールド内に前進する以外の処理はできないものとします。

撃破されたときの処理

敵によって撃破された戦車を初期位置に戻すための処理をおこなうResetメソッドを示します。このメソッドはゲームオーバーになったときにその戦車をNPCにするときにも呼び出されます。

撃破された戦車を復活させる処理を示します。これはTimer.Elapsedイベントによって呼び出されるイベントハンドラです。そこで最初にタイマーを停止させて戦車の復活場所を求めています。また残機が0になった場合はゲームオーバーのイベントを発生させます。

ゲームを開始するための処理を示します。スコアをリセットして残機数を最大値に設定しています。

砲撃にかんする処理

次に砲撃に関する処理を示します。

Bulletクラスの定義

最初に弾丸を管理するためのBulletクラスを示します。

砲撃にかんするイベントの定義

次にPlayerクラスの砲撃にかんするイベントを定義します。壁に砲弾が命中したらクライアントサイドで爆破の演出と壁を非表示にする処理をおこなわなければなりません。また戦車に命中した場合も効果音を鳴らすためにクライアントサイドに知らせる必要があります。そのため引数で座標も同時に渡しています。

Bulletプロパティ

砲弾が壁か戦車にあたるまで次の弾は発射できません。発射した弾丸を管理するためのBulletプロパティを示します。連射できないのでリストにする必要はありません。

砲弾を発射する

砲弾を発射する処理を示します。前回発射した弾丸が着弾していない場合は発射できません。また戦車がフィールドの外にあたり死亡している場合も発射できません。発射処理をおこなうときは戦車の向きに応じて適切な初速を与えます。そしてクライアントサイドに通知するためのイベントを発生させます。

砲弾の更新処理

弾丸を移動させる処理を示します。

砲弾の移動可能範囲を取得し、再利用できるようにフィールド変数に格納しておきます。そして砲弾の移動可能範囲を超えたら爆発させて次の砲弾を発射可能にします。また破壊可能な壁に命中した場合はWall.Breakメソッドを呼び出してその壁を破壊します。

NPCの動作

次にNPCを動作させる処理を示します。

すでに砲弾を発射している場合は砲弾を移動させます。そのあと64分の1の確率で砲撃可能であれば砲弾を発射させます。またすでに方向転換処理または移動処理が開始されている場合はこれを継続し、開始されていない場合は前進できるか、左右に移動可能かをしらべてそのなかからランダムに次の行動を選択させます。

ただし方向転換したあとまた方向転換をくりかえし、同じところをグルグル回り続けることを避けるため、前回の行動が方向転換の場合、つぎに前進できる場合は前進処理をおこなわせます。

最後に 仕上げ

最後にプレイヤーとNPC共通の更新処理を示します。ConnectionIDが空文字列でないなら普通のプレイヤーなのでUpdatePlayerメソッドで処理をおこないます。ConnectionIDが空文字の場合はNPCなので上記で定義したUpdateNPCメソッドを呼び出して処理をおこなわせます。