Skip to content
第22回 敵の物理と巡回状態

2 / 4 敵の重力演算と地形衝突解決

このステップの目的

敵キャラクターに重力加速度と端数蓄積移動を適用し、Stage クラスの衝突解決関数を活用して床や天井と接触させる物理処理を実装します。

敵に必要な物理パラメータの整理

敵キャラクターはプレイヤーのように複雑なジャンプ操作を行いませんが、空中に配置された状態から床へ着地したり、段差を踏み外して落下したりするため、垂直方向の物理演算が必要です。

Enemy.cppcpp
// 向きに応じた一定速度で前進
velocity_.x = facingRight_
    ? tuning::enemy::MoveSpeed
    : -tuning::enemy::MoveSpeed;

// 重力の適用と終端落下速度によるクランプ
velocity_.y = std::min(
    velocity_.y + tuning::enemy::Gravity * deltaTime,
    tuning::enemy::MaxFallSpeed);

水平方向は現在の向きに応じて一定速度で歩行し、垂直方向は重力によって毎フレーム下向きに加速させます。

Stage の衝突解決インターフェースの再利用

敵キャラクターの地形衝突判定を実装する際、タイル配列の走査やめり込み補正の計算を Enemy クラス内に重複して記述する必要はありません。第19回で Stage クラスに構築した軸分離衝突解決メソッドを活用します。

Enemy.cppcpp
bool Enemy::MoveHorizontal(const Stage& stage, float deltaTime)
{
    remainderX_ += velocity_.x * deltaTime;
    const int pixelMove = static_cast<int>(remainderX_);
    remainderX_ -= static_cast<float>(pixelMove);
    if (pixelMove == 0)
        return false;

    dxgame::Rect movedRect = GetHitbox();
    const bool hitWall = stage.ResolveHorizontal(movedRect, pixelMove);
    position_.x = movedRect.GetCenter().x;

    if (hitWall)
    {
        velocity_.x = 0.0f;
        remainderX_ = 0.0f;
    }

    return hitWall;
}
Enemy.cppcpp
void Enemy::MoveVertical(const Stage& stage, float deltaTime)
{
    remainderY_ += velocity_.y * deltaTime;
    const int pixelMove = static_cast<int>(remainderY_);
    remainderY_ -= static_cast<float>(pixelMove);

    if (pixelMove != 0)
    {
        dxgame::Rect movedRect = GetHitbox();
        if (stage.ResolveVertical(movedRect, pixelMove))
        {
            velocity_.y = 0.0f;
            remainderY_ = 0.0f;
        }
        position_.y = movedRect.GetCenter().y;
    }

    dxgame::Rect groundProbe = GetHitbox();
    groundProbe.y += 1.0f;
    onGround_ = stage.IsSolidAtRect(groundProbe);
    if (onGround_ && velocity_.y >= 0.0f)
    {
        velocity_.y = 0.0f;
        remainderY_ = 0.0f;
    }
}

地形判定ロジックを Stage に集約する理由

地形との当たり判定や押し戻し処理の規則(タイルとの境界比較やイプシロンマージン)はすべて Stage クラスが保持しています。

敵キャラクターが Stage の内部配列を直接操作するのではなく、ResolveHorizontal()ResolveVertical() という共通の問い合わせインターフェースを呼び出すことで、コードの重複を防ぎ、ステージの判定仕様に変更があった場合でも修正範囲を1箇所に限定できます。

チェックリスト
  • 敵キャラクターに重力加速度と終端速度クランプを適用できる
  • Stage::ResolveHorizontal() および ResolveVertical() を活用して地形とのめり込みを解消できる
  • 接地時に垂直速度と移動端数を0クリアし、床へのめり込みを防ぐ仕組みを説明できる

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