第05回 プレイヤーを狙う敵弾
3 / 4 敵の発射処理とタイマー制御
このステップの目的
敵に発射タイマーを持たせ、目標となるプレイヤー座標を渡して敵弾の生成を依頼する処理を実装します。
敵の発射間隔とタイマーの管理
敵もプレイヤーと同じく、毎フレーム無制限に撃たず、一定間隔で射撃します。
第02回のTryShootと同様に、発射できる時刻かを調べてから弾の生成を依頼します。
まずEnemy.hのdxgame::shooting名前空間で、Enemyクラスの手前へclass EnemyShotManager;を追加してください。続いて、同クラスのpublicとprivateに以下を追加します。
Enemy.hcpp
public:
// 発射間隔を確認し、目標位置へ向けて敵弾を発射できたらtrueを返す
bool TryShoot(EnemyShotManager& shots, const Vector2& targetPosition);
private:
Vector2 GetMuzzlePosition() const;
// 次の発射までの残り時間(秒)
float shotTimer = 0.0f;Enemy.cppでは既存のインクルードに次を追加します。
Enemy.cppcpp
#include "Shooting/Tuning/GameTuning.h"
#include "Shooting/EnemyShotManager.h"Spawn()でageを初期化する行の下に、最初の発射までの待ち時間ShotDelayを設定します。2発目以降の間隔にはShotIntervalを使います。使用する前に、GameTuning.hのnamespace enemyへ2つの定数を追加してください。
GameTuning.h(namespace enemy内)cpp
inline constexpr float SpawnDelay = 0.40f;
inline constexpr float ShotDelay = 0.80f;
inline constexpr float ShotInterval = 1.80f;Enemy.cpp(Spawn内)cpp
age = 0.0f;
shotTimer = tuning::enemy::ShotDelay;
hp = tuning::enemy::MaxHp;Enemy.cppの同じ名前空間内へ、発射する関数を追加します。
Enemy.cppcpp
bool Enemy::TryShoot(EnemyShotManager& shots, const Vector2& targetPosition)
{
if (!isActive || shotTimer > 0.0f)
return false;
if (!shots.Spawn(GetMuzzlePosition(), targetPosition))
return false;
shotTimer = tuning::enemy::ShotInterval;
return true;
}プールが満杯で弾を生成できなければ、タイマーはリセットしません。空きができたら、すぐに発射を試みます。
タイマーの減算と銃口位置
Enemy::Update()内で、毎フレームdeltaTime分だけタイマーを減算します。
Enemy.cpp の Update に追加cpp
age += deltaTime;
shotTimer -= deltaTime;
position.y += moveSpeed * deltaTime;敵弾は機体の下側から出るほうが自然に見えるため、中心から下方向(+Y方向)へずらした位置を銃口にします。
Enemy.cppcpp
Vector2 Enemy::GetMuzzlePosition() const
{
Rect hitbox = GetHitbox();
return
{
hitbox.GetCenter().x,
hitbox.y + hitbox.height + tuning::enemyShot::Hitbox.height * 0.5f
};
}Gameから敵へ目標位置を渡す
Gameは、前回の命中判定で使ったEnemyManager::GetAll()で敵を順に取り出します。Player::GetHitbox().GetCenter()で求めた自機の中心を、各EnemyのTryShoot()へ渡します。次のステップでGame::Update()へ接続します。
チェックリスト
- 敵が自身の発射タイマー
shotTimerを独立して管理している - 弾の生成に成功した場合のみタイマーがリセットされている
- 出現時の待ち時間と、発射後の待ち時間を設定する場所を区別できる
- 銃口位置が機体の下端になることを式から確認できる(画面での確認は次のステップで行う)