ASP.NET coreで対戦型『スペースウォー!』(Spacewar!)をつくる(3)の続きです。今回はクライアントサイドの処理を定義します。

cshtml部分

style.cssとapp.jsを相対urlで指定していますが、これらのファイルはwwwroot\space-war-appフォルダ内につくります。

Pages\space-war-app\game.cshtml

wwwroot\space-war-app\style.css

定数とグローバル変数

次にJavaScript部分を示します。最初に定数とグローバル変数を示します。

wwwroot\space-war-app\app.js

ページが読み込まれたときの処理

ページが読み込まれたときの処理を示します。

canvasのサイズを調整し、画像ファイルを読み込んで描画に使うイメージを初期化します。イベントリスナを追加して効果音をレンジスライダーで調整できるようにします。そのあとASP.NET SignalRのハブに接続を開始します。

イベントリスナの追加

イベントリスナを追加する処理を示します。

ボタンがクリック、タップ時のイベントリスナーを示します。

回転処理と加速処理はボタンが押下されている間だけおこないます。PCでmousedownしてずらし別のところでmouseupしたときにボタン押下状態が解除されないことを防ぐために①の処理を定義しています。

ゲーム中にプレイヤー名を変更可能なのでキーが押されたらそのつどプレイヤー名も送信します。接続されていない場合(connectionID == ”のとき)はなにもしません。

PCでキーを押下した時のイベントリスナーを示します。

ボリュームの調整

ボリュームをレンジスライダーで調整できるようにする処理を示します。

ボリュームのテストをする処理を示します。

接続成功時の処理

ハブに接続し成功したときの処理を示します。この場合はサーバーサイドからASP.NET SignalRで使われる接続の一意のIDが送られてくるのでそれをグローバル変数に保存し、接続が成功した旨を表示します。

通信が切れてしまったときの処理は以下のようになります。画面に通信が切断された旨を表示します。

エントリー時の処理

エントリーをしてサーバーサイドで正常に処理がおこなわれた場合はサーバーサイドからエントリーしたユーザーに’SucceedEntryToClient’が送信されます。この場合はエントリーした旨を表示し、エントリーボタンを非表示にします。

エントリーし対戦相手を待っているユーザーがいる場合は全ユーザーにそのプレーヤー名を送信します。このときプレーヤー名に<や>があるかもしれないのでエスケープ処理をおこなっています。

マッチング成功時の処理

マッチングが成功したときの処理を示します。

マッチングが成功したときはサーバーサイドから対戦する2人のユーザーにgameNumberとともに’SucceedMatchingToClient’イベントが送信されます。この場合は対戦リストや待機ユーザーが表示されている要素を非表示にして、対戦中であることを示すisPlayingフラグをセットします。また送られてきたgameNumberをplayGameNumberに保存します。そしてマッチング成功の効果音を鳴らします。

試合放棄時の処理

試合放棄があったときの処理を示します。サーバーサイドから試合放棄があったことと自身が勝者であることを示すメッセージとともに’ByeWinToClient’イベントが送信されます。送信の対象になるのは試合放棄をしたプレーヤーの対戦者です。またそのプレーヤー番号が0だった場合はその対戦を観戦していた全ユーザーにも送信されます。

この場合はisPlayingフラグのクリア、エントリー用ボタン、対戦リストや待機ユーザーが表示されている要素を再表示、効果音の再生がおこなわれます。

対戦終了時の処理

対戦が正常に終了した場合はサーバーサイドから’GameFinishedToClient’イベントが送信されます。

観戦の開始時・終了時の処理

ユーザーが別のプレイを観戦しようとしたとき、やめようとしたときの処理を示します。

[観戦する]ボタンをクリックしたときは、観戦を希望しているgameNumberとともに、サーバーサイドに’WatchGame’が送信されます。またこのときはどれを観戦しているのかがわかるようにグローバル変数watchGameNumberにgameNumberが保存されます。以降は更新処理時に観戦しているユーザーにもプレイの状態が描画されるようになります。

観戦をやめるときはこれまで観戦していたwatchGameNumberとともに’StopWatchGame’をサーバーサイドに送信します。また以降はどれも観戦していない状態になるのでグローバル変数watchGameNumberには-1が格納されます。また再び観戦できるように観戦用のボタンが表示され、観戦をやめるボタンは非表示になります。

更新時の処理

サーバーサイドから’UpdateGameToClient’イベントが送信された場合は描画の更新処理がおこなわれます。同時に送られてくるJSONテキストをparseして適切な描画をおこないます。

描画は現在の対戦数、プレイを観戦するためのボタン(これらは対戦者本人には文字列が表示される要素が非表示なので見えない)、対戦しているプレーヤーの機体、中心にある太陽、爆発の火球など(見えるのは対戦しているユーザーと観戦しているユーザーのみ。死亡時の機体は非表示)です。

更新イベントをうけとったユーザーがプレーヤーや観戦者であるかどうかはJSONテキストをparseして得られるGameNumberの値とwatchGameNumberやplayGameNumberに格納されている値を比較すればわかります。観戦している最中にエントリーした場合はゲームのプレーヤーであり観戦者でもあると判定されます。この場合は「プレーヤー」であることを優先して描画処理をおこないます。

太陽の描画

canvasの中央に太陽を描画する処理を示します。

火球のイメージの生成と取得

描画する火球のイメージを生成して取得する処理を示します。一度生成されたものは配列に格納して生成にかかる時間を短縮します。

弾丸発射時の処理

弾丸の発射処理がおこなわれた場合はサーバーサイドから’ShotToClient’が送信されます。送信の対象になるのは弾丸を発射したプレーヤーと、そのプレーヤー番号が0のときは観戦している全ユーザーです。

連続発射されたときに前の発射音が再生中でも現在の発射音が再生されるようにしなければなりません。そこで同じ効果音のAudioオブジェクトをshotSounds配列に格納して交互に再生処理をおこなっています。

爆発発生時の処理

爆発が発生したときはサーバーサイドから’ExplodedToClient’イベントが送信されます。この場合は効果音を鳴らします。送信の対象になるのは対戦している2人のプレーヤーとこれを観戦している全ユーザーです。