ASP.NET Core版 対戦型Pengoをつくる(1)の続きです。

Pengoでは氷のブロックを飛ばして敵を倒します。そこでブロックの座標と状態を格納するためのBlockクラスを定義します。

Blockクラスの定義

以降は名前空間を省略して書きます。

コンストラクタとプロパティ

コンストラクタを示します。

Blockクラスのプロパティです。Pengoではブロックは移動する場合があります。フィールドは15×15ですが、ブロックがこのどの部分にあるのかを示しているのがColumnとRowです。また表示される座標を示しているのがXとYです。TimeUntilDisappearsは破壊されたブロックが消滅するまでの時間であり、KickPlayerはブロックを飛ばしたプレイヤーです(点数計算のときに必要になる)。

ブロックを飛ばしたときの処理

ブロックはそのむこうがわに壁や他のブロックが存在しない場合、飛ばすことができます。一度動き始めたブロックは壁かほかのブロックにぶつかるまで動き続けます。

プレイヤーがブロックを飛ばしたときの処理を示します。

移動中の処理

ブロックが移動している場合、どこかで止めなければならないのですが、それをチェックするための処理を示します。

ブロックのXY座標がCHARACTER_SIZEで割り切れるときにColumnとRowの座標を更新します。そして他のプレイヤーに衝突していないか調べます。そのあとさらなる移動先が壁やその他のブロックでないか調べます。それ以上移動できない場合はそこで動きを止めます。

当たり判定

移動中のブロックが他のプレイヤーに衝突していないか調べる処理を示します。すでに衝突されたプレイヤーを2回カウントしないように注意します。そしてブロックに衝突したプレイヤーの死亡フラグをセットし、そのプレイヤーをリストのなかに格納します。

ブロックを止める

ブロックを止める処理を示します。フラグをクリアしてイベントを発生させます。

IsMovingメソッドはブロックが移動中かどうかを返すだけです。

ブロックを壊す

移動させることができないブロックは壊すことになります。Breakメソッドでは_breakingフラグをセットしているだけです。また移動中のブロックを壊すことはできません。

更新時の処理

ブロックの更新処理を示します。

_breakingフラグがセットされているのであれば崩壊を進行させます。TimeUntilDisappears(消滅までの時間)が0になったらGame.Blocksから取り除きます。

移動中である場合はその方向に移動させます。そのあとCheckStopメソッドで停止するのかどうか、他のプレイヤーとの当たり判定をおこないます。

Playerクラスの定義

以降は名前空間を省略して書きます。

コンストラクタとプロパティ

コンストラクタを示します。引数はAspNetCore.SignalRで接続したときに定まるconnectionIdです。コンストラクタのなかでプレイヤー名とスコアを初期化して残機数に最大値をセットします。

プロパティを示します。

プレイヤーは移動できるか?

上下左右に移動できるかどうかを調べる処理を示します。

移動しようとする方向にブロックがあればそれを返すメソッドを示します。

プレイヤーがブロックを蹴ったとしてブロックを飛ばすことができるかどうかを返すメソッドを示します。

ブロックを飛ばす or 壊す

ブロックがあるならブロックを飛ばす、または壊す処理を示します。

プレイヤーを移動させる

プレイヤーを移動させる処理を示します。

キーが押されているかどうかを調べて移動できるのであれば移動させます。移動が開始されたら移動が完了するまで他の動作はできません。移動先にブロックがある場合は飛ばすことができるのであれば飛ばして、できない場合は破壊します。

プレイヤー死亡時の処理

プレイヤーが死亡時の処理を示します。

プレイヤー死亡時は2秒後に残機1を減らして2秒後に復活させます。ただしプレイヤー(NPCは対象外)の残機が0になった場合はゲームオーバーとします。

復活時は後述するResetメソッドによって、ゲームに参加したときの初期位置に戻されます。ゲームに参加したときの初期位置はPlayerNumberプロパティで決まります。また復活したところを狙い撃ちさせないために、復活してから約3秒間(1 / 24秒 × 24 × 3)は無敵状態とし、他のプレイヤーが飛ばしたブロックにあたってもミスにはならないようにします。

NPCの動作

NPCの移動方向の決め方ですが、ブロックがない方向とブロックがあるけど飛ばすことができる方向をまず取得します。もし取得できなかった場合はブロックを壊すことで移動できる方向を取得します。

取得できた方向がひとつしかない場合はその方向に移動させます。複数ある場合はそのなかから前回の移動方向の逆方向を取り除きます。これは同じところを行ったり来たりさせないためです。これで移動方向の候補が複数ある場合は乱数で決めます。

あとはプレイヤーと同じです。移動を開始したら移動が完了するまでほかの動作はできません。