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

2 / 4 敵の出現制御とレーン分割 ​

このステップの目的

出現タイマーとレーン分割を使い、画面上端から規則的に敵を出現させながら、動きに変化をつけます。

敵の出現アルゴリズム ​

敵の出現間隔と出現位置は、難易度やゲームのテンポを決める重要な要素です。

この作品では、画面の横幅を均等に分けたレーンを用意します。タイマーが0になるたびに敵を1体出し、次のレーンへ進みます。端まで進んだら最初のレーンへ戻り、この順序を繰り返します。

出現パラメータの外部定義 ​

敵の出現間隔やレーンの間隔は、ゲームバランスを調整しながら何度も変更する値です。
コード内に数値を直接書くハードコードを避け、GameTuning.hに定義します。

GameTuning.hcpp
namespace enemy
{
    // 出現レーンの設定
    inline constexpr int LaneCount = 8;         // レーンの総数(8分割)
    inline constexpr float LaneStart = 64.0f;    // 最も左側のレーンのX座標
    inline constexpr float LaneSpacing = 72.0f;  // レーン間の距離

    // 出現間隔(秒)
    inline constexpr float SpawnInterval = 0.6f;

    // 速度とパターンの変化ルール
    inline constexpr int SpeedLevels = 3;
    inline constexpr float BaseSpeed = 120.0f;
    inline constexpr float SpeedStep = 20.0f;
    inline constexpr int WaveInterval = 4;      // 4体に1体の割合で波状移動にする
}

調整値をまとめておくと、レーン数や出現間隔を変更しやすくなります。

出現タイマーによる周期管理 ​

EnemyManager::Update()では、まず現在有効なすべての敵の移動を更新し、続いて出現タイマーを減算します。

EnemyManager.cppcpp
void EnemyManager::Update(float deltaTime)
{
    for (Enemy& enemy : enemies)
        enemy.Update(deltaTime);

    spawnTimer -= deltaTime;

    if (spawnTimer <= 0.0f)
    {
        SpawnOne();
        spawnTimer = tuning::enemy::SpawnInterval;
    }
}

タイマーが0以下になったらSpawnOne()を呼び出して敵を1体出現させ、タイマーを基準値(SpawnInterval)に再設定します。

レーン計算と敵パラメータの決定 ​

敵を1体出現させるSpawnOne()では、停止中の敵スロットを探し、出現番号(spawnIndex)に基づいて出現位置、移動速度、移動パターンを算出します。

EnemyManager.cppcpp
void EnemyManager::SpawnOne()
{
    // spawnIndexから出現レーン、速度、移動方法を順番に決める
    for (Enemy& enemy : enemies)
    {
        if (enemy.IsActive())
            continue;

        int speedLevel = spawnIndex % tuning::enemy::SpeedLevels;
        float speed = tuning::enemy::BaseSpeed + speedLevel * tuning::enemy::SpeedStep;
        int lane = spawnIndex % tuning::enemy::LaneCount;
        Vector2 startPosition =
        {
            tuning::enemy::LaneStart + lane * tuning::enemy::LaneSpacing,
            0.0f
        };

        Enemy::Behaviour pattern =
            (spawnIndex + 1) % tuning::enemy::WaveInterval == 0
                ? Enemy::Behaviour::Wave
                : Enemy::Behaviour::Straight;

        enemy.Spawn(startPosition, speed, pattern);
        ++spawnIndex;

        return;
    }
}

剰余演算子(%)による規則的な変化 ​

spawnIndexは、敵が出現するたびに1増える通算カウンタです。
剰余演算子%で割った余りを使い、次のように規則的な変化をつけます。

  1. レーンの循環: spawnIndex % 8により、出現位置は0 〜 7のレーンを順番にループします。
  2. 速度の段階変化: spawnIndex % 3により、速度が3段階(120、140、160ピクセル/秒)で周期的に切り替わります。
  3. 移動タイプの切り替え: (spawnIndex + 1) % 4 == 0により、4回に1回の頻度で直進から波状移動(Wave)へと変化します。

プールが満杯で空きがなければ、何もせずに関数を終了します。この場合もタイマーで次の出現まで待ちます。上限を超えて生成せず、クラッシュを防ぎます。

チェックリスト
  • LaneStartとLaneSpacingを用いて等間隔なレーン座標が計算されている
  • 出現タイマーによって一定周期でSpawnOne()が呼び出されている
  • 剰余演算子を用いて、出現レーン、移動速度、移動パターンに規則的な変化がつけられている
  • プール内の停止中の敵スロットのみを再利用して出現させている