たくさんの物体を動かすと、ゲームだけでなくメニュー操作まで重くなる。そうした状況で候補になるのが、描画や計算をWeb Workerへ分ける設計です。OffscreenCanvasを導入すれば、どんな作品でも軽くなるわけではありません。この記事では、API資料で確認できるcanvasの移譲と、自分のゲームで比較するための役割分担を整理します。完成したエンジンの内部を無理に書き換える前に、小さな処理で試しましょう。

この記事でわかること

  • 描画を分ける前に、操作を妨げる処理を特定する
  • DOMと入力の窓口はメイン側に残す
  • メッセージ量、終了処理、代替構成も比較する
この記事の目次
  1. 1. DOMの画面と、ゲームの処理の境界を作る
  2. 2. canvasを移す前に、既存のcontext取得を確認する
  3. 3. 入力は小さなメッセージにして渡す
  4. 4. メニューの反応と終了処理まで比較する

1. DOMの画面と、ゲームの処理の境界を作る

MDNはOffscreenCanvasを、DOMとcanvasの描画を分け、Workerの中でも利用できるAPIとして説明しています。描画を別の実行環境に移せることが特徴です。どの仕事を移すかはゲーム側の設計であり、すべてのライブラリがそのままWorkerに入るとは限りません。

この記事の役割分担案では、HTMLのメニュー、画面サイズの取得、入力の窓口をメイン側に置き、ゲームの計算と描画をWorker側にまとめます。音や外部サービスなど、利用しているAPIに依存する処理は別途確認します。まずゲームの進行が画面のDOMを直接読まない構成にすると、処理を分けるための準備になります。

作業前には、操作が遅れる場面を一つ選びます。敵を増やしたときだけ遅いのか、素材を読み込むときに遅いのかで移す候補は変わります。Workerとの通信にも処理が必要なので、メイン側の仕事が小さい作品では分割の複雑さが増えるだけになることもあります。導入前と後で同じ場面を比較できる準備が重要です。

2. canvasを移す前に、既存のcontext取得を確認する

transferControlToOffscreen()の資料では、すでにgetContext()で描画コンテキストを設定したcanvasや、移譲済みのcanvasではInvalidStateErrorが起こると説明されています。移譲するかどうかは、既存の描画初期化が進む前に決める必要があります。

以下は開始時の分岐だけを示す例です。移した後にWorkerが起動しなかった場合は、新しいcanvasを作り直して代替構成へ戻すなど、失敗経路も用意します。同じcanvasを使い回して何度でも初期化できるという想定を置かず、開始、稼働、終了の状態を分けると管理しやすくなります。

const canvas = document.querySelector('#game-canvas');
if (typeof canvas.transferControlToOffscreen === 'function') {
  const worker = new Worker('/game-worker.js', { type: 'module' });
  const offscreen = canvas.transferControlToOffscreen();
  worker.postMessage({ type: 'init', canvas: offscreen }, [offscreen]);
} else {
  // メイン側で動く構成へ進む。
}

3. 入力は小さなメッセージにして渡す

入力イベントをそのまま共有する構成ではなく、「右への移動を開始」「移動を解除」「画面の条件が変化」のようなメッセージを定義します。必要な座標や要求番号だけを渡せば、DOMの詳細がゲームのルールに入り込みにくくなります。Workerから戻す情報も、スコアや状態の変化など、表示側で必要な項目に絞ります。

この記事の通信設計案は、連続する位置情報と、一度だけ起こす決定操作を分けることです。連続位置は最新値へまとめられる場合がありますが、決定操作を途中で消すとゲームの進行が変わります。メッセージには種類と順序を持たせ、ゲーム終了後に届いた古い入力を採用しないようにします。数を増やす前に、開始と終了だけの最小経路を通しましょう。

  • init:描画領域と初期設定
  • input:操作の種類と必要な値
  • resize:描画側へ伝える表示条件
  • state:メイン側で表示するゲーム状態
  • stop:終了と片付け

4. メニューの反応と終了処理まで比較する

比較するのはゲームの描画だけではありません。負荷の高い場面でメニューが開けるか、音の設定が操作できるか、終了後に次のゲームを始められるかも見ます。Workerを終了させたつもりでも古い通知を受け続ける状態がないか、開始を繰り返して複数の処理が動かないかを確認します。

対象端末でWorker版とメイン側の構成を比べ、入力の反応、処理の量、素材準備の違いを残します。記事中のコードは構造を示す例であり、速度改善の実測値を示していません。描画ライブラリがWorker利用を案内していない場合は、その対応範囲を先に調べましょう。メイン側に残る重い処理が原因なら、描画を移す作業とは別の改善が必要です。

メイン側の案内とWorker側の状態がずれる場合は、画面へ表示する状態の番号を付ける方法もあります。終了したゲームから届いたスコアが次のゲームに出るような問題は、描画の分離だけでは防げません。開始ごとに識別できる情報を持ち、表示側が現在の処理の通知だけを採用する構成にすると、再挑戦を繰り返した場合の確認を整理できます。

参考にした情報源

情報確認日:2026.10.14。

記事の訂正はお問い合わせからご連絡ください。