ライフサイクルの適切な境界で登録する
描画関数や毎フレームの処理からwindowのkeydownハンドラーを登録するのは避けてください。シーン固有の初期化は開始時またはマウント時の関数に置き、その関数が後片付けなしで二度実行されないようにします。removeEventListenerを使う場合はコールバックへの参照を保持してください。毎回作り直す無名関数は、後から対応するものを指定して解除するのが困難です。別の方法として、関連するハンドラーをAbortControllerでまとめ、リスナーのオプションにそのsignalを渡し、シーンの終了時にまとめてabortできます。
イベントの対象も慎重に選びます。ゲームがアクティブな間、キー入力に対してwindow全体のリスナーを使うのは適切な場合がありますが、ボタンのclickハンドラーはそのボタンに登録します。イベントの伝播を意図的に利用する設計でない限り、親要素の委譲ハンドラーと直接のハンドラーの両方を同じ操作に登録しないでください。
シーンへの再入場を症状確認として試す
シーンを開いて操作を一度実行し、シーンを離れてから再び開きます。一度の入力で起きる効果が一つであることを確認してください。このサイクルを5回繰り返し、押すたびに反応が一回だけ起きることを確かめます。これは機能の確認であり、メモリー使用量の測定ではありません。退出後に前のシーンへの入力がそのスコアや状態を変えないことも確認します。MDNは、AbortSignalを使ってリスナーをまとめて管理できることを説明しており、明示的に解除する無名関数については参照を保持する必要があるとしています。
所有者に合わせて後片付けする
シーンを切り替えるときは、そのリスナーが参照するオブジェクトを破棄する前に、リスナーをabortするか解除します。アプリ全体のシェルに属するリスナーがある場合は、各ラウンドで解除するのではなく、より長く存続する所有者に持たせます。再起動、一時停止、メニューへの復帰で同じシーンを誤って二重にマウントしたり、後片付けを飛ばしたりしないよう、回帰テストを追加してください。
ゲームのイベントリスナーの重複を防ぐについての質問
キーを一度押しただけで、ゲーム内の操作が複数回起きるのはなぜですか?
同じ操作に複数のハンドラーが登録されているか、親要素と子要素の両方がイベントを処理している可能性があります。登録数を数え、シーンのライフサイクル境界でイベントの伝播を確認してください。
AbortControllerでイベントリスナーを解除できますか?
できます。同じsignalを指定して関連するリスナーを登録し、所有者が終了したときにabortを呼び出します。これでまとめて解除する明確な経路を作れますが、誰がそれらを所有するかを決める必要はあります。
関連情報
古い情報を見つけましたか? 訂正を連絡