2 / 4 発射方向の計算と正規化
目標位置と発射位置の差から方向ベクトルを求め、正規化によって弾速を一定にそろえる計算方法を理解します。
2点間の差から方向ベクトルを求める
敵弾を発射位置(startPosition)からプレイヤーの位置(targetPosition)へ飛ばすには、まず目標がどちらの方向にあるかを求めます。
点Aから点Bへの向きと距離を表すベクトルは、「終点の座標(目標)
Vector2 direction =
{
targetPosition.x - startPosition.x,
targetPosition.y - startPosition.y
};たとえば、敵の座標が{ 100, 200 }で、プレイヤーの座標が{ 130, 240 }にある場合、差分ベクトルは次のようになります。
この{ 30, 40 }という値は、発射位置から見た目標の「向き」と「距離」の双方を含んでいます。
ベクトルの正規化(長さを1にする処理)
差分ベクトル{ 30, 40 }をそのまま速度に使うと、重大な問題が起きます。
目標が遠いほど値が大きくなって弾が速く進み、近いほど値が小さくなって遅くなります。
位置関係にかかわらず弾速を一定にするには、差分ベクトルの長さを1にそろえ、向きだけを使います。この計算をベクトルの正規化(Normalization)と呼びます。
三平方の定理による長さの算出
直角三角形の斜辺の長さを求める三平方の定理(ピタゴラスの定理)を用いて、差分ベクトルの長さ(2点間の直線距離)を計算します。
先ほどの例(
成分を長さで割り、弾速を掛ける
ベクトルの各成分を自身の長さ(
この長さ1の単位ベクトルに、弾速(tuning::enemyShot::Speed)を掛けます。これで、目標方向へ一定の速さで進む速度ベクトルvelocityを求められます。
void EnemyShot::Spawn(const Vector2& startPosition, const Vector2& targetPosition)
{
position = startPosition;
Vector2 direction = {
targetPosition.x - position.x,
targetPosition.y - position.y
};
float distance = std::sqrt(direction.x * direction.x + direction.y * direction.y);
// 敵とプレイヤーの位置が異なるためdistanceは0にならない
// 方向を長さ1にそろえ角度によらず同じ速さにする
velocity = {
direction.x / distance * tuning::enemyShot::Speed,
direction.y / distance * tuning::enemyShot::Speed
};
isActive = true;
}ゼロ除算の防止
もし発射位置と目標位置が完全に同一の座標であった場合、距離lengthは0.0fになります。
コンピューターは数値をゼロで割ることができない(ゼロ除算が発生して未定義動作やクラッシュを引き起こす)ため、必ずif (length > 0.0f)の条件チェックを行い、安全性を確保します。
- 終点(目標)から始点(発射位置)を引くことで方向ベクトルが求まることを理解している
- 三平方の定理(
std::sqrt)を用いてベクトルの長さを計算できる - 長さで割る「正規化」によって、距離にかかわらず弾速を均一に保てる理由を説明できる
- ゼロ除算を防ぐための条件分岐(
length > 0.0f)の必要性を理解している