====== 🎯 第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);
|< tablewidth 45% >|
|< 50% 50% >|
^ 記号 ^ 意味 ^
| &(参照渡し) | コピーせずに「元データ」を参照する |
| const | 関数内で変更できない「読み取り専用」にする |
→ **高速で安全** に距離を計算できる!
----
===== 🧮 例題:Enemyクラス =====
**目的:** Playerとの距離を計算し、一定距離以内なら「攻撃できる」と表示する。
#include
#include
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参照で受け渡すことで無駄なコピーを防ぐ。
----
===== 🎯 まとめ =====
|< tablewidth 50% >|
|< 50% 50% >|
^ 覚えるポイント ^ 内容 ^
| const参照 (const &) | データをコピーせず、安全に読み取る(読み取り専用) |
| static関数 | クラスに属するが、特定のインスタンスに依存しない関数 |
| スコープ解決演算子(::) | 所属を明示する。「Vector2D::distance」のように使う |
| あたり判定の考え方 | 「距離 ≤ 範囲」で攻撃や接触を判定する |
----