第05回 プレイヤーを狙う敵弾
1 / 4 敵弾クラスの設計
このステップの目的
任意の方向へ移動できるように、位置だけでなく「速度ベクトル」を保持するEnemyShotクラスを定義します。
敵弾が保持すべき状態とPlayerShotとの違い
第02回で作成したプレイヤー弾(PlayerShot)は、常に画面上方向へまっすぐ進むため、Y座標を一定速度で減算するだけで移動できました。
しかし、敵弾は「発射された瞬間にプレイヤーがいた位置」へ向かって飛ぶため、上下左右あらゆる斜め方向へ進む必要があります。
そのため、EnemyShotには現在位置positionに加え、速度ベクトルvelocityを持たせます。速度ベクトルは、1秒あたりの移動量と向きを表します。
EnemyShot.hcpp
#pragma once
#include "DxGame/Rect.h"
#include "DxGame/Vector2.h"
namespace dxgame::shooting
{
// 敵が発射する1発の弾の位置、速度、実行状態を管理する
class EnemyShot
{
public:
// 中心をstartPositionへ移動し発射時点のtargetPositionへ向かう速度を設定する
// 発射後はtargetPositionを追尾しない
void Spawn(const Vector2& startPosition, const Vector2& targetPosition);
// 発射時の速度で移動し画面外へ出たら停止する
// deltaTimeは1フレームの経過秒数
void Update(float deltaTime);
// 実行中の弾を表示用Rectに合わせて描く
void Draw(const class ImageManager& images) const;
// 更新、描画、命中判定の対象ならtrueを返す
bool IsActive() const;
// 弾を更新、描画、命中判定の対象外にする
void Deactivate();
// 表示用Rectを現在位置へ移動して返す
Rect GetDrawRect() const;
// 現在位置から求めた命中判定用Rectを返す
Rect GetHitbox() const;
private:
// 弾の中心座標
Vector2 position = {};
Vector2 velocity = {};
bool isActive = false;
};
}向きと速さをvelocityに持たせると、どの斜め方向に進む弾も、足し算で位置を更新できます。
速度ベクトルを用いた位置の更新
Update()では、毎フレーム経過時間deltaTimeに応じて座標を進めます。
EnemyShot.cppcpp
void EnemyShot::Update(float deltaTime)
{
if (!isActive)
return;
position.x += velocity.x * deltaTime;
position.y += velocity.y * deltaTime;
// Hitbox全体が画面外へ出た弾を再利用できる状態に戻す
Rect hitbox = GetHitbox();
if (hitbox.x + hitbox.width < 0.0f ||
hitbox.x > tuning::ScreenWidth ||
hitbox.y + hitbox.height < 0.0f ||
hitbox.y > tuning::ScreenHeight)
Deactivate();
}敵弾はあらゆる方向へ飛ぶため、画面外判定は上下左右の4方向で行います。
追尾弾(ホーミング)ではなく狙い撃ち弾にする理由
目標座標(targetPosition)は、発射時のSpawn()だけで受け取ります。メンバ変数には保持しないことが重要です。
毎フレーム自機の座標を参照して方向を計算し直すと、自機を追い続ける追尾弾(ホーミング弾)になります。追尾弾は避けにくく、通常の敵が撃つ基本弾としては難しくなりすぎます。
発射時に一度だけ、目標との差からvelocityを求めて保存します。その後はvelocityだけを使い、一定の速さで直進させます。自機を移動すれば安全にかわせる狙い撃ち弾になり、公平な駆け引きができます。
次のステップでは、このvelocityを算出するベクトル計算(正規化)の仕組みを詳しく見ていきます。
チェックリスト
-
EnemyShotクラスが位置positionと速度ベクトルvelocityを保持している - 速度ベクトルに
deltaTimeを掛けてX座標・Y座標を前進させている - 画面の上下左右の4方向の画面外判定を正しく行っている
- 発射時に目標座標から一度だけ速度を決定し、追尾し続けない設計の理由を説明できる