ASP.NET Core版 対戦型ラリーエックスをつくる(2)の続きです。

AspNetCore.SignalR.Hubクラスを継承してRallyXHubクラスを定義します。

以降は

と書きます。

接続時の処理

クライアントがサーバーサイドに接続したときの処理を示します。

最初の1回だけタイマーの初期化をおこなっています。接続に成功したらクライアントサイドにContext.ConnectionIdを通知しています。また壁の座標と縦横の列数を文字列に変換して通知しています。

接続したときにそのクライアントが最初のユーザーであった場合は、フィールドを初期化します。ここでは壁の追加とNPCの初期化の処理をしています。

NPCの初期化

NPCを初期化する処理はRallyXGameクラスで定義しています。NPCsに格納されているPlayerオブジェクトがあったらクリアして赤青緑のPlayerを3つずつ合計9つ生成しています。Playerクラスのコンストラクタにプレイヤー識別番号を渡すことで自動的に初期位置にセットされます。

GetAllPlayersメソッドは以下のようになっています。これはプレイヤーとNPCの両方のPlayerオブジェクトのリストを返します。

切断されたときの処理

切断されたときの処理を示します。ClientProxyMapのなかから対応するものを取り除きます。そして接続ユーザーが0になった場合はタイマーを止めます。

切断されたユーザーはプレイ中のユーザーかもしれません。そこでContext.ConnectionIdからプレイヤーとして登録されているかを調べます。登録されている場合はそこからも削除します。そのあと接続しているユーザー全員に試合放棄があったことを通知します。

GetPlayerNameFromKeyメソッドはContext.ConnectionIdを引数にプレイヤー名を取得するメソッドです。RallyXGameクラス内で以下のように定義されています。

RemovePlayerFromKeyメソッドはRallyXGameクラス内で以下のように定義されています。

引数に対応するPlayerオブジェクトがPlayers内に存在する場合はこれを削除します。そして新しいNPCを生成してNPCsに追加しています。そして全プレイヤーを色別に分類しています。

ゲームに参加するときの処理

ユーザーがプレイに参加するときの処理を示します。

新しくユーザーがゲームに参加した場合、そのユーザーにはたしかにゲームに参加できたことを、それ以外のユーザーには新しいユーザーがゲームに参加したことを通知します。また新たにゲームに参加したユーザーにはフィールド上に存在する煙幕の位置もあわせて通知します。

上記で呼び出されているRallyXGameクラスのメソッドを示します。

フィールド上に存在する煙幕をクライアントに送信する

以下はフィールド上に存在する煙幕の座標と状態をカンマ区切りの文字列で取得するためのメソッドです。

更新処理

更新処理をおこなう前にクライアントサイドで更新処理をするために必要なデータを取得するための処理を示します。

以下は新しく発生した煙幕のX座標、Y座標、生成したプレイヤーを文字列として取得するためのメソッドです。

以下は消滅する煙幕のX座標、Y座標をカンマ区切りの文字列として取得するためのメソッドです。

以下は未通過のフラッグのX座標、Y座標をカンマ区切りの文字列として取得するためのメソッドです。

以下は火花のX座標、Y座標、消滅までの時間をカンマ区切りの文字列として取得するためのメソッドです。

タイマーでElapsedイベントが発生したら更新処理をおこないます。

RallyXGame.Updateメソッドを呼び出してデータの更新処理をおこない、当たり判定をしています。そのあとSendUpdateToClientメソッドを呼び出してクライアントサイドでの更新処理に必要なデータを送っています。送るデータは同じなので最初にまとめて取得する処理をおこなっています。

煙幕はゲームの進行と時間の経過によって新たに発生したり消滅したりします。これらを毎回すべてのクライアントにすべて送信していては処理に時間がかかるので差分のみを送信します。そのため新しく生成された煙幕を送信したらRallyXGame.EndUpdateメソッドを実行することで、新しく生成された煙幕と既存の煙幕をひとつにまとめています。

RallyXGame.EndUpdateメソッドは新しく発生した煙幕を既存の煙幕と統合しています。IsTimeBetweenStagesプロパティは現在の状態がステージクリア後のステージとステージのあいだにあるかどうかを返します。

更新用のデータをクライアントサイドに送信する

クライアントサイドに更新用のデータを送信する処理を示します。ここでは各プレイヤーの名前、ID、座標、移動方向、燃料と上記の処理で取得した煙幕の状態、フラッグ、火花を文字列にしたものをクライアントサイドに送信しています。

RallyXGame.GetNPCsCountメソッドはNPCの数を返します。

ステージクリア時の文字列を表示させる

ステージクリア後の次のステージが開始されるまでに表示する文字列を送信する処理を示します。ここでは各プレイヤーのボーナスポイントと成績上位者を表示するための文字列を送信しています。

LastFlagPlayerには最後にフラッグを取ったプレイヤーが格納されます。ステージクリアの際に最後にフラッグを取ったプレイヤー名を表示させたいのでここに一時的に格納しています。

データの更新

_updateCount == 0であればステージが開始されるときなのでステージの初期化の処理をおこないます。各PlayerオブジェクトをリセットするとともにStageKillCountプロパティとStageFlagCountプロパティを0に戻します。

_updateCount > 0のときは各オブジェクトの更新処理をおこないます。プレイヤーならUpdatePlayerメソッド、NPCならUpdateNPCメソッドを呼び出したあと、煙幕と火花の状態も更新します。そして煙幕のなかで消滅したものをSmokesDisappearに一時的に保存します。そのあとステージクリア判定をおこないます。

当たり判定

X座標が同じでY軸の差がCHARACTER_SIZE – 8以下の場合、Y座標が同じでX軸の差がCHARACTER_SIZE – 8以下の場合は両者は衝突していると判断します。ただし片方の死亡フラグが立っている場合、または当たり判定によって撃破される側が無敵状態のときはは当たり判定はしません。

衝突している場合は撃破された側のDeadメソッドを呼び出し、火花を発生させます。そしてクライアントサイドにPlayerDeadToClientを送信します。そのあと後述するKillメソッドを呼び出して撃破したプレイヤーに対して加点処理をおこないます。

RallyXGame.SetSparksメソッドは撃破されたプレイヤーの周辺に火花を表示させるための処理をおこないます。

加点処理

撃破したプレイヤーに加点処理をおこなう処理を示します。撃破したプレイヤーには800点が加算されますが、そうでなくても同じ色であれば100点加算されます。

ステージクリア判定

ステージクリアになっているかどうかをチェックする処理を示します。

Flags.Count == 0であればステージクリアです。この場合は_updateCountに負数を代入します。更新処理が1回おこなわれるたびに_updateCountはインクリメントされますが、これが負数の場合はステージクリアから次のステージまでの休止期間であることになります。

ステージクリアであると判定されたら新しいステージをつくります。やることはフラッグの初期化です。

このときに成績優秀者を表示させるための文字列を生成します。フラッグ取得数と撃破数が多いプレイヤーは誰なのかを文字列にして取得します。

ゲームオーバー時の処理

ゲームオーバーになったらすべてのユーザーにこれを通知します。それと同時にスコアをランキングに登録する処理をおこないます。

スコアをランキングに登録する処理を示します。これまでのゲームとほとんど同じことをしています。

キー操作への対応

キー操作がされた場合は方向転換、煙幕の放出をおこないます。

最後にRallyX.RallyXHubをProgram.csに追加します。

Program.cs