ソースコード解説・目次

CHAPTER 17 · 全23項目

演出と描画の高速化

パーティクル、加算合成、ヒットストップと、画像を再利用する工夫を整理します。

主な参照先:spawnBurst / MAX_PARTICLES / updateCommon / removeAt / refreshFormLayer / refreshSky

短い寿命のオブジェクトで演出する

game.html · L1262–1275ソースを見る ↗
// 画面内のパーティクルの上限。ボムで編隊をまとめて倒した時などに、描画が一度に重くなりすぎないようにする。
// 爆発の破片は上限の 24 個手前で止め、自機の噴射と発射炎(多くて 20 個ほど)が上限に当たって消えないようにする。
const MAX_PARTICLES = 400, BURST_PARTICLES = MAX_PARTICLES - 24;

function spawnBurst(x, y, color, n = 12, sp = 110) {
  n = Math.min(n, BURST_PARTICLES - particles.length);
  for (let i = 0; i < n; i++) {
    const a = Math.random() * Math.PI * 2, v = sp * rand(0.35, 1);
    particles.push({
      x, y, vx: Math.cos(a) * v, vy: Math.sin(a) * v,
      life: rand(0.3, 0.7), max: 0.7, color, size: Math.random() < 0.3 ? 3 : 2,
    });
  }
}

爆発はランダムな方向へ進む粒子の集まりです。cos と sin で角度から横・縦の速度を作り、毎フレーム座標を進め、life を減らします。衝撃波は半径が増える rings、得点表示は上へ浮く popups として管理します。

ボムで編隊をまとめて倒すと、1体16個の粒子が一度に何百個も生まれます。そこで画面内の粒子は MAX_PARTICLES(400個)までとします。爆発の破片を作る spawnBurst() は、その24個手前の BURST_PARTICLES(376個)に届いたぶんだけ作る数を減らします。空けておいた分は、自分で MAX_PARTICLES を確かめてから足す自機の噴射と発射炎(多くて20個ほど)に回るので、まとめて倒した直後でも噴射が途切れません。ふだんのプレイで上限に届くことはなく、描画がいちばん重くなる瞬間だけを抑える安全弁です。

描く順序が不要なものは素早く削除する

game.html · L1555–1558ソースを見る ↗
function removeAt(arr, i) {
  const last = arr.pop();
  if (i < arr.length) arr[i] = last;
}

粒子とリングは、消す場所へ配列の末尾を移す方法で削除します。後ろの全要素を詰め直す必要はありません。ただし順序は変わるため、重ねる順番に意味がある処理へそのまま使うことはできません。

光彩は足し合わせ、形は上から重ねる

drawGlowPass() では globalCompositeOperation = "lighter" を使い、光の重なりを明るくします。その後は通常の source-over へ戻して本体を描きます。スプライトや光彩、タイトル、ボス船体などは別のCanvasに先に描いておきます。

変化したときだけ画像を作り直す

対象再利用の方法
編隊本体と光彩を各1枚にまとめ、生存状態・飛行状態・コマ・敵配列が変わったときに更新
星雲背景画像を約15 fpsで更新し、各フレームではコピーする
レーザー柱は幅ごとの画像をキャッシュし、中間部分を引き伸ばす。連結砲から伸びる光の線も連結数ごとに一度だけ描き、毎フレームの shadowBlur をなくす
バリア1つずつ画像にしておき、削れたときだけ描き直す(「10 崩れるバリアの実装」)
ボタンの文言shownButtons と比較し、内容が変わったときだけDOMへ書く

短い停止と画面の揺れ

撃破時の freezeT は updatePlay() の冒頭で戦闘更新を短く止めます。共通の粒子更新は動き続けるため、爆発まで固まることはありません。shake は描画座標だけをランダムにずらし、当たり判定の座標は変えません。