🎯 第6章 距離で判断するオブジェクト:Enemyクラス
🏁 学習目標
- 2つのオブジェクト間の距離を計算できるようにする
- const参照(const &)を使って安全かつ効率的にデータを渡す
- 条件分岐(if)を使って「当たった or 当たっていない」を判定する
💬 あたり判定とは?
ゲームでは、キャラクター同士や攻撃との「距離」で当たりを判定します。
たとえば、 「敵とプレイヤーの距離が 2 以下なら攻撃が届いた」 というように、数値的な距離比較 で処理を行います。
数式で表すと、次のようになります:
$$ 距離 = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2} $$
この考え方は、どんなジャンルのゲームにも共通する基本です。
💡 const参照で安全に距離を測る
距離を計算する関数では、プレイヤーやベクトルのデータをコピーせずに 「読み取り専用」で使いたい場面が多くあります。
double calcDistance(const Vector2D& a, const Vector2D& b);
| 記号 | 意味 |
|---|---|
| &(参照渡し) | コピーせずに「元データ」を参照する |
| const | 関数内で変更できない「読み取り専用」にする |
→ 高速で安全 に距離を計算できる!
🧮 例題:Enemyクラス
目的: 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)」なら「攻撃可能!」という考え方。
🧩 練習問題(第6問)
複数の敵とプレイヤーのあたり判定を作ってみよう。
// クラス: 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」のように使う |
| あたり判定の考え方 | 「距離 ≤ 範囲」で攻撃や接触を判定する |