ASP.NET Core版 対人対戦できるぷよぷよをつくる(4)の続きです。他の人のプレイを観戦できる機能を追加します。

これまでは対戦しているユーザーだけにゲームに関するデータを送信していました。これを観戦したいユーザーにも送信すればよいということになります。では、そのように作りかえましょう。

まず観戦希望者用のページを作成します。

cshtmlファイル

新しくcshtmlファイルをPagesフォルダの配下に作成し、以下のように記述します。

Pages\PuyoMatch\games.cshtml

名前空間は省略します。

対戦リストを表示させる

対戦リストを表示させるためにはクライアントサイドに現在おこなわれているすべての対戦のリストを送信しなければなりません。

そのためにこれまでに使っていたOnConnectedAsyncメソッドに1行追加します。最後に自作メソッド SendGamesToClientを呼び出しているだけです。

SendGamesToClientメソッドは観戦用のページに現在おこなわれている対戦のプレイヤー名とこれを観戦するためのボタンを表示するための文字列を送信するためのものです。

クライアントサイドの処理

次にクライアントサイドの処理ですが、観戦用のページにアクセスしたら現在対戦中のリストをページ内に表示させます。対戦がひとつも行なわれていない場合はそのように表示させます。また観戦をしていないのに[観戦をやめる]ボタンが表示されているのはおかしいので、この最初はボタンを非表示にしておきます。

wwwroot\puyo-match\puyo-match.js

実際に他人の対戦を観戦する

[観戦する]ボタンがクリックされると引数として両対戦者のIDを引数にWatchGame関数が呼び出されます。これを頼りにサーバーサイドでは該当するゲームオブジェクトを探します。

wwwroot\puyo-match\puyo-match.js

観戦者リストに追加する処理

サーバーサイドでは”GetGameToServer”を受信すると以下の処理が行なわれます。

引数で渡されたふたつのIDがPuyoMatchGame.ConnectionIdsプロパティに格納されているオブジェクトを探します。見つかった場合はPuyoMatchGame.AddWatcherメソッドでユーザーを観戦者リストに追加します。そして観戦者として正常に登録されたことを伝えるために”SuccessfulWatchGameToClient”を送信します。

そのあと各データをクライアントサイドに送信します。SendMatchStringメソッドで対戦情報(両プレイヤー名、現在何戦目かなど)を送信します。また次回、次々回に落下するぷよの情報も送信します。

これは観戦者として登録されているユーザーの接続IDのリストを返すメソッドです。また観戦者として追加・削除するためのメソッドもあわせて示します。

ネクストぷよを取得できるようにPuyoMatchGameクラスを修正する

これまでは次回、次々回に落下してくるぷよが決まったら対戦者だけに送信すればよかったのですが、観戦者はいつあらわれるかわからないので、いつでも次回、次々回に落下してくるぷよの情報を取得できるようにします。そのためにNextPuyoTextsプロパティを定義するとともに、既存のメソッドを修正します。

クライアントサイドにおける処理

クライアントサイドで”SuccessfulWatchGameToClient”を受信したときは観戦者登録の処理が正常におこなわれたということなのでフィールドの描画処理ができるようにcanvasを表示させます。

また対戦リストは表示させておいてもじゃまなだけなので非表示にします。かわりに[観戦をやめる]ボタンを表示させます。

データ更新時の処理

PuyoMatchHub.GetClientsメソッドは描画処理のためにデータを送信するユーザーを取得するためのものですが、観戦者にもデータを送信しなければならないので修正します。

回転や着地、連鎖時のイベントが発生したときも、これを対戦者だけでなく観戦者にも通知できるように修正を加えます。

敗戦時の処理

一方が負けたときの処理ですが、長くなるので処理を分けました。

まず勝った側のPuyoMatchGame.WinCounts[n]をインクリメントします。そして後述するSendGameResultメソッドでどちらがどちらに勝ったのか負けたのかをクライアントサイドで表示するための文字列を送信します。

次にCheckGameSetメソッドでゲームセット(片方が3勝している)なのかを調べて、その場合はGamesリストからPuyoMatchGameオブジェクトを除去する処理をおこないます。ゲームセットになっていない場合は3秒間小休止したあと次の対戦がはじまります。

次にゲームセット(片方が3勝している)なのかを調べて、その場合はGamesリストからPuyoMatchGameオブジェクトを除去する処理をおこないます。ゲームセットになっていない場合は3秒間小休止したあと次の対戦がはじまります。

これは勝ち負けそれぞれのプレイヤー名と接続IDを取得するためのメソッドです。

これはクライアントサイドに、誰が誰に勝ったのか負けたのかを表示するための文字列を送信するためのメソッドです。

これはプレイヤーの一方が3勝していたときに対戦者と観戦者に”FinishedGameToClient”を送信してGamesリストからPuyoMatchGameオブジェクトをRemoveするための処理です。

これは次の対戦が開始されたときに対戦者情報をクライアントサイド(対戦者と観戦者)に送信するための処理です。

PuyoMatchGame.NextGameStartメソッドは次の対戦を開始するためのものです。引数がtrueだと前回のスコアをリセットします。

ゲームセット時の処理

ゲームセットになったらゲームをするためのページにおける処理に変更はありません。観戦用のページでは非表示にしていた対戦リストを再表示させます。また[観戦をやめる]ボタンは不要なので非表示にさせます。

観戦をやめるときの処理

[観戦をやめる]ボタンがクリックされるとcanvasは非表示にします。PuyoMatchGameオブジェクト内の観戦者リストから自身を削除する処理をおこなわせるために、サーバーサイドに”RemoveWatcher”を送信します。また対戦リストを表示させるための文字列が必要なので、これを要求するために”SendGamesToClient”を送信します。

サーバーサイドではRemoveWatcherが呼び出されたらPuyoMatchGame.RemoveWatcherメソッドを呼び出して観戦者リストからContext.ConnectionIdを削除します。

試合放棄時の処理

対戦を観戦しているとその対戦で試合放棄がある場合も考えられます。この場合はOnDisconnectedAsyncが呼び出されるので、このなかで処理をおこないます。CheckGameAbandonedメソッド内でこの処理をおこないます。それ以外の部分は既存のOnDisconnectedAsyncメソッドと同じです。

CheckGameAbandonedメソッドでは引数の接続IDをもつユーザーが対戦者の一方であるPuyoMatchGameオブジェクトを探して、残されたプレイヤーに試合放棄があったことを知らせます。それと同時にこれを観戦しているユーザーにも同様の通知をおこないます。そのあとGamesリストから該当するPuyoMatchGameオブジェクトを取り除きます。