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

PengoHubクラスの定義

以降は名前空間を省略して以下のように書きます。

フィールド変数

フィールド変数を示します。

接続したときの処理を示します。

接続されたら接続に成功したことをクライアントサイドに伝えます。そしてContext.ConnectionIdをキーにしてClientProxyMapにClients.Callerを登録します。そしてクライアントサイドに現在マップに存在するブロックの座標を送信します。

はじめて接続されたときはタイマーにイベントハンドラを追加して、タイマーをスタートさせます。

接続した結果、ClientProxyMap.Countが1の場合はフィールドを初期化します。さらにフィールドに追加されたブロックのそれぞれに移動を開始したとき、停止したとき、他のプレイヤーを撃破したとき、破壊されたときのイベントハンドラを追加します。この段階ではユーザーはゲームには参加していません。

切断されたときの処理を示します。

ClientProxyMapとGame.PlayersからContext.ConnectionIdを削除します。また切断された結果、どのユーザーも接続されていない状態になったらタイマーを停止させます。そして他のすべてのユーザーに対してそのユーザーが離脱したことを知らせます。

イベントハンドラの定義

ブロックが移動を開始したときの処理を示します。すべてのクライアントにReceiveBlockKickを送信します。

ブロックが停止したときの処理を示します。このときブロックは他のプレイヤーに衝突しているかもしれません。イベントハンドラの第三引数をみれば撃破したプレイヤーの数がわかるので点数計算をして第二引数のプレイヤーのスコアに加算します。

プレイヤーがブロックを壊したときの処理を示します。すべてのクライアントにReceiveBlockBreakを送信します。

飛ばれたブロックで他のプレイヤーを撃破したときの処理を示します。

第一引数が撃破したプレイヤー、第二引数が撃破されたプレイヤーです。撃破されたプレイヤーの座標を中心に火花を飛び散らせます。

ユーザーがゲームに参加したときの処理

ユーザーがゲームに参加しようとしたときの処理を示します。もしNPCが存在するのであれば先頭の要素を取り除き、新しく生成したPlayerオブジェクトをGame.Playersに追加します。またゲームオーバー時の処理ができるようにイベントハンドラも追加します。最後にクライアントサイドから送られてきたプレイヤー名をセットしてすべてのユーザーに参戦した旨を伝えます。

更新処理

Timer.Elapsedイベントが発生したときの処理を示します。

ここでやっていることはプレイヤー、NPC、ブロック、火花の位置と状態の更新です。更新されたデータはSendUpdateToClientメソッドでクライアントサイドに送信されます。

それからここではブロックの数が少なくなってきたら新しいブロックを追加する処理もしています。

新しいブロックを追加するときはいきなりブロックが出現するとユーザーが困惑するので、その位置にブロックを点滅させます。そして一定時間が経過したらブロックを配置します。

ブロックが出現する位置はGame.GetAddBlockPositionsメソッドで取得できます。これをReceiveBeforeAddBlocksでクライアントサイドに送信します。その2秒後にイベントハンドラTimer_Elapsed1を呼び出して実際にフィールド上にブロックを追加します。

ブロックの追加

ゲームの途中でフィールド上にブロックを追加する処理を示します。このときも新しく追加するブロックのイベントハンドラを追加するのを忘れないように注意します。

クライアントサイドにプレイヤー、ブロック、火花の位置と状態を送信する処理を示します。

引数からゲームに参加しているかどうかを調べます。参加しているのであればplayerNumberに0以上の値が代入されます。その場合はクライアントサイドにReceiveUpdateGameStatusを送信するときに第一引数としてそのまま渡します。参加していない場合でいまからでも参加可能な場合は-1、定員オーバーで参加できない場合は-2を渡します。

ゲームオーバー時の処理

ゲームオーバーになったら、全プレイヤー数がGame.PLAYER_MAXである状態を保つためにNPCを生成します。そしてSaveHiscoreメソッドを呼び出して、スコアランキングに登録する必要がある場合は登録の処理をおこないます。最後に全ユーザーにゲームオーバーになった旨を伝えます。

スコアランキング登録の処理

スコアランキングに登録する処理を示します。

まずプレイヤー情報とスコアを格納するクラスを定義します。

スコアランキングに関する情報はhiscore-pengo.txtに保存します。まずファイルからデータを読み出してHiscoreオブジェクトのリストを生成します。最後にゲームオーバーになったプレイヤーのスコアを追加してスコアが大きい順に並べます。上位から30個取れば上位30位のプレイヤー名とスコアがわかります。これをサイドhiscore-pengo.txtに保存します。

キー操作への対応

ユーザーがキー操作をしたときの処理を示します。ゲームに参加しているのであればクライアントサイドから送られてきたプレイヤー名をPlayer.Nameにセットします。そしてキーの押下状態に応じてPlayer.IsXXXKeyDownプロパティをセットしたりクリアします。

スコアランキングを表示する

スコアランキングを表示させる処理を示します。

ゲームのページと同じフォルダにhi-score.cshtmlをつくります。

Pages\Pengo\hi-score.cshtml