ASP.NET Core版 ボンバーマンのような対戦型ゲームをつくる(1)の続きです。今回はプレイヤーの動作に関する処理を実装します。

Playerクラスの定義

Playerクラスを定義します。

インデントが深くなるので以降は以下のように名前空間を省略します。

コンストラクタ

コンストラクタを示します。引数はASP.NET SignalRを用いて接続したときに取得されるIDです。PLAYER_MAXはゲーム開始時の残機数、INVINCIBLE_TIMEは無敵状態になれる時間です。これが0より大きいときは無敵です。

プロパティ

プレイヤーは15×15のセルの上に存在しますが、CurrentColumnとCurrentRowは現在のセルの位置、NextColumnとNextRowはこれから移動しようとしているセルの位置です。XとYは各プレイヤーが描画されるべきX座標とY座標です。

IsXXXKeyDownプロパティは方向キーが押されているかどうかを管理するものですが、複数の方向キーを同時におすと斜めに移動できるというバグがあることがわかったので、ひとつしかtrueにならないようにしています。

斜め移動できてしまうバグ

各プレイヤーの初期位置は四隅のどこかになりますが、撃破されてしまった場合、初期座標に戻されます。このときResetNumberの値でどこに戻されるかを切り分けるようにします。それ以外のName、Rest、Score、IsDeadの各プロパティはプレイヤーの表示名、残機、スコア、生きているかどうかを示すものです。

それから新しくプレイヤーがゲームに参加したときにNPCのうちひとつが取り除かれ、新たなプレイヤーとなって隅に移動するのですが、これがバグっぽく見えてしまいます。配信者さんもこの現象にちょっと驚いているようです(下の動画では新たにプレイヤーがゲームに参加したことでニワトリが突然左上にワープしたようにみえる。しかも参加したプレイヤーがキー操作をしないとプレイヤー名も表示されない)。

突然キャラクタがワープ?

そこで新しくプレイヤーがゲームに参加したときはそのプレイヤーを点滅させる、新たな参戦者が現れたことを全観戦者に通知するようにしました。これなら違和感はそんなにないと思います。

InvincibleTimeプロパティは新しくプレイヤーがゲームに参加したとき、爆弾によって撃破されてしまったあと隅に移動した場合、INVINCIBLE_TIMEがセットされます。このプロパティが0以上のときはプレイヤーが点滅して当たり判定はなしにします。

移動に関する処理

最初にその方向に移動できるかどうかを調べる処理を示します。移動可能かどうかの判定はここではブロックがあるかどうかだけで判断しています。

次に更新処理がおこなわれるときにキーが押されているかどうかで上下左右に移動させる処理を示します。

ここでは最初にXプロパティとYプロパティをGame.CHARACTER_SIZEで割り切れるかどうかを調べています。割り切れるのであればセルからセルの移動は完全に完了している状態です。この状態の場合だけキー入力による移動の開始処理をおこなっています。IsXXXKeyDownプロパティを調べてその方向に移動できるのであれば、_movingXXXフラグをtrueにして移動を開始しています。

_movingXXXフラグがtrueの場合はキー入力による移動の開始処理はおこなわず、すでに開始されている移動処理を継続します。移動処理をおこなった結果、XプロパティとYプロパティがGame.CHARACTER_SIZEで割り切れる場合は移動が完了したということなので_movingXXXフラグをクリアしています。

爆弾をセットする処理

爆弾をセットする処理を示します。ここではBombオブジェクトを生成してからGameクラスのSetBombメソッドを呼び出しているだけです。

プレイヤーが次のセルに移動している最中に設置ボタンがおされるかもしれません。そこで爆弾はNextColumnとNextRowの位置にセットします。プレイヤーの移動が完全に完了している状態ではCurrentColumnとNextColumn、CurrentRowとNextRowが一致しているので問題はありません。

リセットの処理

ゲームに参加したとき、爆発に巻き込まれて死亡したときは初期位置に移動します。そのための処理を示します。

引数なしのResetメソッドが呼び出された場合はすでに保存されているResetNumberプロパティの値が使用されます。

死亡時の処理

爆発に巻き込まれて死亡したときの処理を示します。一定時間をあけて初期位置に移動させるとともに一時的に無敵状態にします。またプレイヤーの場合は残機を1減らして残機0になった場合はゲームオーバーの処理をおこなうことができるようにイベントを定義しておきます。

NPCの動作

NPCの動作を決める処理を示します。

まず移動方向の決め方ですが、その方向に移動したとして爆弾の影響から逃れられるかどうかを調べます。また爆弾を設置する場合、そこに爆弾を設置した場合、逃げることができるかどうかも調べます。

CanEscapeBombメソッドでは引数で渡されたdangerMapをコピーして二次元配列を生成して、元の位置に戻らずにある方向に移動して爆弾の影響範囲外に逃げられるかを調べています。

現在位置から壁や爆弾がある場所を通らず繋がったセルを取得して安全な位置にたどり着くことができるかどうかを調べています。一度調べた場所にはチェックをつけて一度調べた場所を何度も調べないようにしています。

更新処理をするときにCanEscapeBombメソッドで取得した結果を利用してNPCを移動させる処理を示します。