Skip to content
第03回 敵の出現と移動

1 / 4 敵1体分の処理を分ける

このステップの目的

敵1体の位置、移動、実行状態をEnemyへ分け、複数管理の準備をする

PlayerShotとの共通点

第02回のPlayerShotは、1発分の位置と実行状態を持っていました。 敵も同じように、1体分の情報をEnemyへまとめます。

ただし、敵は下方向へ移動し、出現時に速度や移動方法が異なります。 同じManagerの型へ無理にまとめず、敵専用のクラスを作ります。

Enemy.hcpp
class Enemy
{
public:
    enum class Behaviour
    {
        Straight,
        Wave
    };

    void Spawn(const Vector2& startPosition, float speed, Behaviour behaviour);
    void Update(float deltaTime);
    void Draw(const ImageManager& images) const;
    bool IsActive() const;

private:
    Vector2 position = {};
    float baseX = 0.0f;
    float moveSpeed = 0.0f;
    float age = 0.0f;
    Behaviour movement = Behaviour::Straight;
    bool isActive = false;
};

Spawn()では、敵を再利用するために位置、速度、経過時間、移動方法をまとめて初期化します。 停止するときは削除せず、isActivefalseへ戻します。

Enemy.cppcpp
void Enemy::Spawn(const Vector2& startPosition, float speed, Behaviour behaviour)
{
    position = startPosition;
    baseX = startPosition.x;
    moveSpeed = speed;
    age = 0.0f;
    movement = behaviour;
    isActive = true;
}

void Enemy::Deactivate()
{
    isActive = false;
}

Managerを最初から用意する

EnemyManagerは敵を所有し、停止中の敵を再利用します。 この回では敵を1体だけ表示するための一時的なメンバをGameへ追加しません。

第02回で確認した「Gameは集合の処理をManagerへ依頼する」という関係を、そのまま敵へ適用します。

EnemyManager.hcpp
static constexpr std::size_t Capacity = 24;
std::array<Enemy, Capacity> enemies = {};

編集するファイルの順番

設計を一から考える必要はありません。次の順番で、1つずつ追加します。

  1. Source/Shooting/Enemy.hへ、Spawn()Update()Draw()IsActive()Deactivate()、矩形取得関数を宣言する。
  2. Source/Shooting/Enemy.cppへ、1体分の位置、移動、描画、有効状態の処理を実装する。
  3. Source/Shooting/EnemyManager.hへ、std::array<Enemy, Capacity>とManagerの公開関数を追加する。
  4. Source/Shooting/EnemyManager.cppへ、配列を順番に更新・描画する処理を追加する。

迷ったら、PlayerShotPlayerShotManagerの「個体」と「集合」の分担を横に並べて確認します。 この回では、敵の種類を増やしたり、Gameへ敵の配列を移したりしません。

チェックリスト
  • Enemyが1体分の位置と実行状態を持っている
  • EnemyManagerが複数の敵を所有する責任を持っている
  • Gameに敵の個体を直接追加していない