Appearance
第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()では、敵を再利用するために位置、速度、経過時間、移動方法をまとめて初期化します。 停止するときは削除せず、isActiveをfalseへ戻します。
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つずつ追加します。
Source/Shooting/Enemy.hへ、Spawn()、Update()、Draw()、IsActive()、Deactivate()、矩形取得関数を宣言する。Source/Shooting/Enemy.cppへ、1体分の位置、移動、描画、有効状態の処理を実装する。Source/Shooting/EnemyManager.hへ、std::array<Enemy, Capacity>とManagerの公開関数を追加する。Source/Shooting/EnemyManager.cppへ、配列を順番に更新・描画する処理を追加する。
迷ったら、PlayerShotとPlayerShotManagerの「個体」と「集合」の分担を横に並べて確認します。 この回では、敵の種類を増やしたり、Gameへ敵の配列を移したりしません。
チェックリスト
-
Enemyが1体分の位置と実行状態を持っている -
EnemyManagerが複数の敵を所有する責任を持っている -
Gameに敵の個体を直接追加していない