Skip to content
第05回 プレイヤーを狙う敵弾

1 / 4 敵弾クラスの設計 ​

このステップの目的

任意の方向へ移動できるように、位置だけでなく「速度ベクトル」を保持するEnemyShotクラスを定義します。

敵弾が保持すべき状態とPlayerShotとの違い ​

第02回で作成したプレイヤー弾(PlayerShot)は、常に画面上方向へまっすぐ進むため、Y座標を一定速度で減算するだけで移動できました。
しかし、敵弾は「発射された瞬間にプレイヤーがいた位置」へ向かって飛ぶため、上下左右あらゆる斜め方向へ進む必要があります。

そのため、EnemyShotには現在位置positionに加え、速度ベクトルvelocityを持たせます。速度ベクトルは、1秒あたりの移動量と向きを表します。

EnemyShot.hcpp
#pragma once

#include "DxGame/Rect.h"
#include "DxGame/Vector2.h"

namespace dxgame::shooting
{
    // 敵が発射する1発の弾の位置、速度、実行状態を管理する
    class EnemyShot
    {
    public:
        // 中心をstartPositionへ移動し発射時点のtargetPositionへ向かう速度を設定する
        // 発射後はtargetPositionを追尾しない
        void Spawn(const Vector2& startPosition, const Vector2& targetPosition);

        // 発射時の速度で移動し画面外へ出たら停止する
        // deltaTimeは1フレームの経過秒数
        void Update(float deltaTime);

        // 実行中の弾を表示用Rectに合わせて描く
        void Draw(const class ImageManager& images) const;

        // 更新、描画、命中判定の対象ならtrueを返す
        bool IsActive() const;

        // 弾を更新、描画、命中判定の対象外にする
        void Deactivate();

        // 表示用Rectを現在位置へ移動して返す
        Rect GetDrawRect() const;

        // 現在位置から求めた命中判定用Rectを返す
        Rect GetHitbox() const;

    private:
        // 弾の中心座標
        Vector2 position = {};
        Vector2 velocity = {};
        bool isActive = false;
    };
}

向きと速さをvelocityに持たせると、どの斜め方向に進む弾も、足し算で位置を更新できます。

速度ベクトルを用いた位置の更新 ​

Update()では、毎フレーム経過時間deltaTimeに応じて座標を進めます。

EnemyShot.cppcpp
void EnemyShot::Update(float deltaTime)
{
    if (!isActive)
        return;

    position.x += velocity.x * deltaTime;
    position.y += velocity.y * deltaTime;

    // Hitbox全体が画面外へ出た弾を再利用できる状態に戻す
    Rect hitbox = GetHitbox();
    if (hitbox.x + hitbox.width < 0.0f ||
        hitbox.x > tuning::ScreenWidth ||
        hitbox.y + hitbox.height < 0.0f ||
        hitbox.y > tuning::ScreenHeight)
        Deactivate();
}

敵弾はあらゆる方向へ飛ぶため、画面外判定は上下左右の4方向で行います。

追尾弾(ホーミング)ではなく狙い撃ち弾にする理由 ​

目標座標(targetPosition)は、発射時のSpawn()だけで受け取ります。メンバ変数には保持しないことが重要です。

毎フレーム自機の座標を参照して方向を計算し直すと、自機を追い続ける追尾弾(ホーミング弾)になります。追尾弾は避けにくく、通常の敵が撃つ基本弾としては難しくなりすぎます。

発射時に一度だけ、目標との差からvelocityを求めて保存します。その後はvelocityだけを使い、一定の速さで直進させます。自機を移動すれば安全にかわせる狙い撃ち弾になり、公平な駆け引きができます。

次のステップでは、このvelocityを算出するベクトル計算(正規化)の仕組みを詳しく見ていきます。

チェックリスト
  • EnemyShotクラスが位置positionと速度ベクトルvelocityを保持している
  • 速度ベクトルにdeltaTimeを掛けてX座標・Y座標を前進させている
  • 画面の上下左右の4方向の画面外判定を正しく行っている
  • 発射時に目標座標から一度だけ速度を決定し、追尾し続けない設計の理由を説明できる