ASP.NET coreで対戦型『スペースウォー!』(Spacewar!)をつくる(2)の続きです。今回はASP.NET Core用のSignalRで使用するHubクラスを定義します。

Program.csの編集

まずASP.NET Coreで新しいプロジェクトを作成したときに自動生成されるProgram.csを編集します。

Program.cs

このあとSpacewarApp.GameHubを定義します。

Hubクラスの定義

以降は名前空間部分を省略して表記します。

フィールド変数

静的フィールド変数として以下を定義します。

SignalR によって割り当てられる一意のIDから、そのユーザーが対戦しているゲームに対応するGameオブジェクトとPlayerオブジェクトを取得する処理を示します。

接続のイベント処理

接続のイベントが発生したときにおこなわれる処理を示します。

切断のイベント処理

切断のイベントが発生したときにおこなわれる処理を示します。

他のユーザーと対戦中のユーザーが通信を切断した場合は相手に対して試合放棄されたことを通知します。また対戦相手を待っているユーザーが通信を切断した場合も待機しているユーザーがいなくなったことを全ユーザーに通知します。

キー操作がおこなわれたときの処理

キー操作がおこなわれたときの処理を示します。

キーが押下されたときの処理を示します。

クライアントサイドから送られてきたプレーヤー名が空文字列の場合は”名無しさん”とします。キー操作で待機中のユーザーや対戦中のユーザーの名前が変更された場合があるので、その場合は変更の処理をおこないます。

対戦中のユーザーがキー操作をおこなったときはユーザーに対応するPlayerオブジェクトを取得し、それぞれに適切なフラグのセット、クリア、メソッドの呼び出しをおこないます。また弾丸の発射処理が正常におこなわれたときはそのユーザーと観戦者に対して効果音を再生するためのイベントを送信します(ただし観戦者に対してはPlayer0による発射時のみ)。

キーが離されたときの処理を示します。

エントリー時の処理

ユーザーがエントリーをしたときの処理を示します。

待機ユーザーがいないときはエントリーをしたユーザーが待機ユーザーとなり、対戦相手が見つかるまで待機し続けることになります。この処理が正常におこなわれた場合は”SucceedEntryToClient”イベントをエントリーしたユーザーに送信して処理が正常におこなわれたことを通知します。

すでに待機ユーザーがいる場合はそのユーザーと対戦することになります。エントリーしたユーザーと待機していたユーザーに”SucceedMatchingToClient”イベントを送信してマッチングの成功と対戦がはじまることを通知します。

対戦が始まるときはまずGameオブジェクトを生成します。WaitingPlayerはnullにしてGameオブジェクトに爆発発生時とゲーム終了時のイベントハンドラを追加します。そしてこれをすぐにGamesリストに追加しないで一時保存します(すぐに追加してしまうとforeach文が実行されたときに例外が発生するので、明らかにそうではないタイミングで追加する)。

爆発発生時のイベントハンドラ

爆発発生時のイベントハンドラを示します。

爆発発生時は対戦しているユーザーと観戦しているユーザー全員に”ExplodedToClient”イベントを送信します。

対戦終了時のイベントハンドラ

対戦終了時のイベントハンドラを示します。

対応するGameオブジェクトはGamesリストから削除しますが、すぐには削除しないで削除用のリストに一時保存します。これは例外発生を防ぐためです。次に勝者と敗者に”あなたは勝ちました。”または”あなたは負けました。”の文字列とともに”GameFinishedToClient”イベントを送信します。また観戦しているユーザー全員に対してもPlayer0が勝ったのか負けたのかを示す文字列とともに”GameFinishedToClient”イベントを送信します。

観戦の開始と終了

観戦を開始したり終了する処理を示します。

ユーザーはgameNumberを指定して観戦に参加することができます。参加する場合はgameNumberと同じ値をもつGameオブジェクトのWatcherIdsにConnectionIdを追加し、やめる場合はWatcherIdsからConnectionIdを削除します。

更新時の処理

更新時の処理を示します。更新時にはGamesとClientProxiesでforeach文を実行しますが、その前に要素の追加と削除をおこないます。そのあとGameオブジェクトを更新して全ユーザーにデータ(プレーヤーや弾丸の位置など)を送信します。

foreach文を実行する前に要素の追加と削除をする処理を示します。

ユーザー全員に待機しているユーザーの名前を送信する処理を示します。

“○○があなたとの対戦を待っています”と画面上に表示させたいのですが、エントリーした本人の場合、”(自分の名前)があなたとの対戦を待っています”というのはおかしいので、その場合はなにも表示させません。待機しているユーザーがいない場合は”現在 誰もエントリーしていません”と表示させます。