第03回 敵の出現と移動
1 / 4 敵クラスと管理クラスの設計
このステップの目的
敵1体分の状態を持つEnemyクラスと、敵の集合を管理するEnemyManagerの構造を定義します。
弾の管理構造を敵キャラクターへ適用する
第02回で作成したプレイヤー弾(PlayerShot)は、弾1発分の位置と有効フラグを保持していました。
敵キャラクターも同様に、敵1体分の情報と振る舞いをカプセル化したEnemyクラスを定義します。
敵は個体ごとに出現位置や速度が異なります。直進に加え、左右に揺れる動きもあります。そのため、移動パターンを切り替える状態をメンバ変数に持たせます。
Enemy.hcpp
#pragma once
#include "DxGame/Rect.h"
#include "DxGame/Vector2.h"
namespace dxgame::shooting
{
class ImageManager;
// 敵一体の位置、移動、表示、実行状態を管理する
// 敵1体の位置、移動、表示、実行状態を管理する
class Enemy
{
public:
// 下方向へ直進するか左右へ波打ちながら進むかを表す
enum class Behaviour
{
Straight,
Wave
};
// 中心座標、速度、移動方法を設定して敵を出現させる
void Spawn(const Vector2& startPosition, float speed, Behaviour spawnBehaviour);
// 敵を移動させ、画面の下へ出たら停止する
void Update(float deltaTime);
// 実行中の敵を画像で描く
void Draw(const ImageManager& images) const;
// 更新と描画の対象ならtrueを返す
bool IsActive() const;
// 敵を更新と描画の対象外にする
void Deactivate();
// 表示用Rectを現在位置へ移動して返す
Rect GetDrawRect() const;
private:
Vector2 position = {};
float baseX = 0.0f;
float moveSpeed = 0.0f;
float age = 0.0f;
Behaviour behaviour = Behaviour::Straight;
bool isActive = false;
};
}baseXは波状移動の中心となるX座標です。ageには出現後の経過時間を記録し、波の計算に使います。
敵の初期化と停止
Spawn()では、出現時に必要なパラメータを受け取ってすべてのメンバ変数を初期化し、isActiveをtrueに設定します。
Enemy.cppcpp
void Enemy::Spawn(const Vector2& startPosition, float speed, Behaviour spawnBehaviour)
{
position = startPosition;
baseX = startPosition.x;
moveSpeed = speed;
age = 0.0f;
behaviour = spawnBehaviour;
isActive = true;
}
bool Enemy::IsActive() const
{
return isActive;
}
void Enemy::Deactivate()
{
isActive = false;
}画面外への到達や、後の回で実装する撃破処理によって停止させる場合は、Deactivate()を呼び出してisActive = falseに戻します。
敵を統括するEnemyManagerの構造
敵も弾と同じく多数が出現するため、固定長配列を用いたEnemyManagerで一括管理します。
EnemyManager.hcpp
#pragma once
#include <array>
#include <cstddef>
#include "Shooting/Enemy.h"
namespace dxgame::shooting
{
// 敵の管理クラス
class EnemyManager
{
public:
// すべての敵を停止し、出現順と最初の出現待ち時間を初期化
void Reset();
// すべての敵を更新する 出現タイマーを進め、必要なら敵を生成する
// すべての敵を更新する(出現タイマーを進め、必要に応じて敵を生成)
void Update(float deltaTime);
// アクティブなすべての敵を描画する
void Draw(const class ImageManager& images) const;
private:
// 停止中の要素を再利用しゲーム中にはメモリを確保しない
static constexpr std::size_t Capacity = 24;
// 停止中の敵を1体選び出現順に応じた設定で生成する
// 空きがない場合は何もしない
void SpawnOne();
std::array<Enemy, Capacity> enemies = {};
float spawnTimer = 0.0f;
int spawnIndex = 0;
};
}敵の最大同時出現数は24体(Capacity = 24)として設定します。EnemyManagerは、毎フレームの更新と描画をループでまとめて実行します。タイマーを管理し、一定間隔で新しい敵を出現させる役割も持ちます。
チェックリスト
-
Enemyクラスが位置、速度、経過時間、移動挙動、有効フラグを保持している -
Behaviour列挙型によって敵の挙動を表現できる設計になっている -
EnemyManagerが固定配列(Capacity)を用いて敵をプール管理している - 敵単体の責任(
Enemy)と全体の集合管理の責任(EnemyManager)の違いを説明できる