Skip to content
第23回 トラップとゲーム進行

3 / 4 敵接触を踏みつけとダメージへ分ける

このステップの目的

プレイヤーと敵の当たり判定が重なった際、プレイヤーの運動方向と幾何学的な位置関係から「踏みつけ撃破」と「被弾(ゲームオーバー)」を適切に判別する処理を実装します。

接触判定の対象を活動中の敵に限定する

敵との当たり判定は、登録されているすべての敵を調べるのではなく、現在活動中(IsActive())の敵のみを対象にします。

cpp
for (Enemy& enemy : enemies_.GetAll())
{
    if (!enemy.IsActive())
        continue;

    const dxgame::Rect enemyHitbox = enemy.GetHitbox();
    if (!playerHitbox.Overlaps(enemyHitbox))
        continue;

    // 重なりが確認された敵に対して踏みつけ判定を行う
}

すでに倒されて消滅した敵との不要な判定をスキップすることで、処理負荷を抑えるとともに非表示の敵との誤衝突を防止します。

踏みつけ判定の幾何学的条件

プレイヤーの足底と敵領域の重なり方を、以下の2つの条件で判別します。

cpp
const float playerBottom = playerHitbox.y + playerHitbox.height;
const float enemyMiddle = enemyHitbox.y + enemyHitbox.height * 0.5f;

const bool stomped = player_.GetVelocity().y > 0.0f &&
    playerBottom <= enemyMiddle;
[プレイヤー] (velocity.y > 0: 落下中)
+----------+
|          |
+----------+ <- playerBottom
------------------------- <- enemyMiddle (敵の中央ライン)
|          |
+----------+
[   敵   ]

1. 落下運動中であること(velocity_.y > 0.0f

プレイヤーが上向きにジャンプしている最中に下から敵に接触した場合は、踏みつけではなく被弾として処理する必要があります。そのため、Y軸速度が下向き(正)であることを必須条件とします。

2. 足底が敵の中央ラインより上にあること(playerBottom <= enemyMiddle

基準線を敵の天面(enemyHitbox.y)ではなく「高さ中央(enemyMiddle)」に設定するのには理由があります。

フレーム単位の離散的な位置更新では、高速で落下しているプレイヤーが1フレームの間に敵の天面を通過し、体の中央付近まで深く進入することがあります。もし判定ラインを天面ちょうどの位置にしてしまうと、上方から踏みつけたにもかかわらず「天面より下にあるため側面からの衝突」と誤判定されてしまいます。

敵の上半分(中央より上)に足底が位置していれば踏みつけと判定するマージンを設けることで、落下速度が大きい場合でも安定した踏みつけ判定が成立します。
※より厳密な判定が必要な場合は、前フレームのプレイヤー足底位置と比較して交差を検証する手法(連続衝突判定)が用いられます。

踏みつけ成功時と被弾時の分岐

cpp
if (stomped)
{
    enemy.Defeat();
    player_.BounceFromEnemy();
    return false; // ゲームオーバーにはならない
}

return true; // 側面や下からの接触はゲームオーバー

踏みつけに成功した場合は、敵を撃破(Defeat)状態にし、プレイヤーを上空へ小さく跳ね返らせます(BounceFromEnemy)。これにより、敵を踏み台として連続して移動するアクションが成立します。

一方、踏みつけ条件を満たさなかった接触(側面や下部からの接触)は被弾とみなし、関数は true を返してゲームオーバーへと遷移させます。

チェックリスト
  • 活動中の敵のみを対象に当たり判定の重なりを走査できる
  • 落下速度(velocity_.y > 0)と足底の位置関係から踏みつけを幾何学的に判定できる
  • 高速落下時の誤判定を防ぐために敵の中央ラインを基準線とする理由を説明できる
  • 踏みつけ成功時に敵撃破とプレイヤーの跳ね返りを実行できる

ゲームプログラミング実践