ソースコード解説・目次

CHAPTER 09 · 全23項目

弾の移動と衝突の順序

配列の逆順走査、弾が消える条件、シールドとミスの分岐を説明します。

主な参照先:pBullets / eBullets / damagePlayer / hitPlayer

弾は位置と速度を持つオブジェクト

game.html · L1726–1733ソースを見る ↗
  // --- 自弾 ---
  for (let i = pBullets.length - 1; i >= 0; i--) {
    const p = pBullets[i];
    p.y -= SHOT_SPEED * dt;
    p.x += (p.vx || 0) * dt;
    // 自機の弾は自陣のバリアを素通りする(バリアは敵弾から身を守るためのもの)。
    let dead = p.y + p.h < 0 || p.x < -20 || p.x > W + 20;
    if (!dead) {

自弾は毎秒 SHOT_SPEED = 600 pxで上へ進み、横方向の速度がある弾は xも変化します。画面外へ出たら削除対象です。敵弾は各オブジェクトの vy、必要なら vx を使って進めます。ボスの3方向弾や、自機を狙って斜めに飛ぶ狙い撃ちの弾(赤く描く aimed の弾)が vx を持ちます(「07 敵の編隊とウェーブ生成」)。

通常弾の長さ SHOT_H は14 pxです。dt の上限0.05秒のフレームでは弾が30 px進みますが、これが敵の高さ16 pxと弾の長さ14 pxの合計を超えないため、弾が敵を飛び越えて当たり損ねることはありません。

衝突を調べる順番にも意味がある

順番自弾の処理
1画面外かどうかを調べる
2敵弾と相殺する
3ボーナス円盤、ボスとの衝突を調べる
4通常の敵に当たれば撃破し、弾を消す

dead が true になった弾は後続の対象を攻撃しません。連結ビームも通常弾と同じく、最初に当たった1体を倒した時点で消え、貫通はしません。自機の弾はバリアを調べないので、通常弾・3方向ショット・連結ビームのどれも自陣のバリアを素通りします。バリアを削るのは敵弾と、重なった敵だけです。合体レーザーは別の処理です。

削除しながら調べるなら後ろから

splice(i, 1) は要素を消し、後ろの要素を前へ詰めます。前から進むループだと、詰まってきた要素を飛ばすことがあります。末尾から先頭へ調べれば、まだ調べていない要素の位置は変わりません。

シールドと残機減少を分ける

game.html · L1539–1551ソースを見る ↗
function damagePlayer() {
  waveNoDamage = false;
  resetCombo();
  if (active.shield > 0) {
    active.shield = 0;
    player.inv = 1.2;
    spawnRing(player.x, PLAYER_Y + 8, "#7dff7a", 240, 0.4);
    popup(player.x, PLAYER_Y - 24, "SHIELD BREAK", "#7dff7a", 12);
    sfx.shieldBreak();
    return;
  }
  hitPlayer();
}

ダメージを受けると、まずノーダメージ記録とコンボを解除します。シールドがあればそれを消費し、1.2秒の無敵時間を与えます。シールドがなければ hitPlayer() が残機を減らし、連結砲を BEAM_LOSS の2門だけ減らして dying に移します。ミスの演出中は円盤も止まるので、円盤の効果音もここで止め、プレイに戻る時に鳴らし直します(演出中にタブを隠しても音が鳴り続けないように)。射撃中かどうかを表す shooting は消さないので、射撃ボタンを押し続けていれば復帰後もそのまま撃てます。