====== 🎯 第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」のように使う | | あたり判定の考え方 | 「距離 ≤ 範囲」で攻撃や接触を判定する | ----