🎯 第6章 距離で判断するオブジェクト:Enemyクラス

  • 2つのオブジェクト間の距離を計算できるようにする
  • const参照(const &)を使って安全かつ効率的にデータを渡す
  • 条件分岐(if)を使って「当たった or 当たっていない」を判定する

ゲームでは、キャラクター同士や攻撃との「距離」で当たりを判定します。

たとえば、 「敵とプレイヤーの距離が 2 以下なら攻撃が届いた」 というように、数値的な距離比較 で処理を行います。

数式で表すと、次のようになります:

$$ 距離 = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2} $$

この考え方は、どんなジャンルのゲームにも共通する基本です。


距離を計算する関数では、プレイヤーやベクトルのデータをコピーせずに 「読み取り専用」で使いたい場面が多くあります。

double calcDistance(const Vector2D& a, const Vector2D& b);
記号 意味
&(参照渡し) コピーせずに「元データ」を参照する
const 関数内で変更できない「読み取り専用」にする

高速で安全 に距離を計算できる!


目的: Playerとの距離を計算し、一定距離以内なら「攻撃できる」と表示する。

#include <iostream>
#include <cmath>
using namespace std;
 
// ======================
// Vector2D クラス
// ======================
class Vector2D {
public:
    double x;
    double y;
    Vector2D(double a, double b);
    static double distance(const Vector2D& a, const Vector2D& b);
};
 
// ---- Vector2D メンバ関数の外部定義 ----
Vector2D::Vector2D(double a, double b) {
    x = a;
    y = b;
}
 
double Vector2D::distance(const Vector2D& a, const Vector2D& b) {
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}
 
// ======================
// Player クラス
// ======================
class Player {
public:
    string name;
    Vector2D pos;
    Player(string n, Vector2D p);
    void show();
};
 
Player::Player(string n, Vector2D p) {
    name = n;
    pos = p;
}
 
void Player::show() {
    cout << name << " の位置: (" << pos.x << ", " << pos.y << ")" << endl;
}
 
// ======================
// Enemy クラス
// ======================
class Enemy {
public:
    string name;
    Vector2D pos;
    double range;   // 攻撃可能距離
 
    Enemy(string n, Vector2D p, double r);
    bool canAttack(const Player& target);
    void show();
};
 
// ---- Enemy メンバ関数の外部定義 ----
Enemy::Enemy(string n, Vector2D p, double r) {
    name = n;
    pos = p;
    range = r;
}
 
bool Enemy::canAttack(const Player& target) {
    double d = Vector2D::distance(pos, target.pos);
    return d <= range;
}
 
void Enemy::show() {
    cout << name << " の位置: (" << pos.x << ", " << pos.y << ")" << endl;
}
 
// ======================
// main 関数
// ======================
int main() {
    Player p("Hero", Vector2D(0, 0));
    Enemy  e("Slime", Vector2D(1, 1), 2.0);
 
    p.show();
    e.show();
 
    double dist = Vector2D::distance(p.pos, e.pos);
    cout << "距離: " << dist << endl;
 
    if (e.canAttack(p)) {
        cout << e.name << " は " << p.name << " を攻撃できる!" << endl;
    } else {
        cout << e.name << " はまだ届かない…" << endl;
    }
}

実行結果

Hero の位置: (0, 0)
Slime の位置: (1, 1)
距離: 1.41421
Slime は Hero を攻撃できる!

ポイント

  • const & により、Playerの情報をコピーせずに読み取っている。
  • distance()static 関数として定義し、どの位置同士でも距離を測れる。
  • canAttack() が距離を条件に攻撃可否を判断する。

(0,0)  プレイヤー(Hero)
  ↓ 距離 1.41
(1,1)  敵(Slime)

「距離 ≤ 攻撃範囲(range)」なら「攻撃可能!」という考え方。


複数の敵とプレイヤーのあたり判定を作ってみよう。

// クラス: Enemy, Player, Vector2D(同様の定義)
//
// main()の仕様:
//   ・プレイヤーを (0,0) に配置
//   ・敵を3体作る:
//       Enemy("Slime",  Vector2D(1,1), 2.0)
//       Enemy("Bat",    Vector2D(3,4), 2.0)
//       Enemy("Orc",    Vector2D(5,1), 3.0)
//   ・それぞれについて canAttack() を使い、攻撃可能か判定して表示
//
// 出力例:
// Slime は Hero を攻撃できる!
// Bat はまだ届かない…
// Orc はまだ届かない…

ヒント

  • Vector2D::distance() を再利用する。
  • canAttack() をループの中で呼び出して判定する。
  • const参照で受け渡すことで無駄なコピーを防ぐ。

覚えるポイント 内容
const参照 (const &) データをコピーせず、安全に読み取る(読み取り専用)
static関数 クラスに属するが、特定のインスタンスに依存しない関数
スコープ解決演算子(::) 所属を明示する。「Vector2D::distance」のように使う
あたり判定の考え方 「距離 ≤ 範囲」で攻撃や接触を判定する

  • game-engineer/classes/2025/game-development-1/no-08-6.txt
  • 最終更新: 3カ月前
  • by root