学習記事一覧 · ターン制OOP入門

【学習】ターン制バトルで学ぶオブジェクト指向(5)ターン制バトル 〜同じ型で扱う・ポリモーフィズム〜

第4回までで WarriorMageCharacter の派生 として整理できました。

ここがオブジェクト指向の 核心 です。

WarriorMage を、両方とも Character として扱う

そうすると、ターン制のループでは 「今攻撃しているのが戦士か魔導士か」 を都度 if で分けずに済みます。


今回の最小ゴール

  • Character 型の変数・配列に WarriorMage を入れる
  • while で交互に攻撃し、どちらかの Hp が 0 以下になったら終了する
  • attacker.GetPower()実体に応じた計算 になることを説明できる

前回からの差分

  • Character warrior = new Warrior(...); のように 親型の変数に子の実体 を入れる
  • Character[] で2人を管理
  • ターン交代に % 2(剰余)を使う

ソリューションとプロジェクトを作る

  • テンプレート: コンソール アプリ
  • プロジェクト名: TurnBattleOop05(任意)

第4回の Character / Warrior / Mage 定義をそのまま使います。


同じ型として並べる

Character warrior = new Warrior("せんし", 100, 20);
Character mage = new Mage("まどうし", 80, 25);

Character[] characters = { warrior, mage };

左辺が Character であることに注目してください。配列の要素型も Character です。


ターン制バトル

internal class Program
{
    private static void Main(string[] args)
    {
        Character warrior = new Warrior("せんし", 100, 20);
        Character mage = new Mage("まどうし", 80, 25);
        Character[] characters = { warrior, mage };

        int turn = 0;

        while (true)
        {
            Character attacker = characters[turn % 2];
            Character defender = characters[(turn + 1) % 2];

            int damage = attacker.GetPower();
            defender.Hp -= damage;

            Console.WriteLine(attacker.Name + "の攻撃!");
            Console.WriteLine(defender.Name + "に " + damage + " のダメージ");

            if (defender.Hp <= 0)
            {
                Console.WriteLine(defender.Name + "は倒れた!");
                break;
            }

            turn++;
        }
    }
}

なぜ % 2 なのか

  • turn0, 1, 2, 3, ... と増えるとき、turn % 20, 1, 0, 1, ... と交互になる
  • characters[0]characters[1]交互に攻撃者にする のに使っています

人数が増える場合は、別のデータ構造やインデックスの取り方に変えます(本記事は 2人対戦 に絞ります)。


このコードの本当の意味(ポリモーフィズム)

次の1行だけに注目します。

int damage = attacker.GetPower();

attacker の型は Character です。ところが 実際のオブジェクトWarrior なら力ベース、Mage なら魔法ベースで、中身の計算が変わります

呼び方は同じ、動きは実体ごとに違う

これが ポリモーフィズム(多態性) です。


プログラムの流れ

2人を Character 配列に入れる

turn で攻撃者・防御者を交互に選ぶ

attacker.GetPower() でダメージ(中身は実体依存)

defender.Hp を減らし、0 以下なら終了

WinForms / Unity での当たり所

要素 本回 WinForms Unity
リスト Character[] List<Character> キャラ参照のリスト
ターン進行 while ボタン1回=1ターン コルーチン / 状態機械
同じ呼び方 GetPower() モデルの同一メソッド インターフェースや基底クラス経由

重要ポイント(授業で伝えたい3つ)

  1. 最初から抽象化しなくていい … 第3回のように重複が見えてからでよい
  2. 継承は整理のための仕組み … 重複を減らし、ルールをはっきりさせる
  3. GetPower() の1行が価値 … 種類が増えても、ループ側を書き換えにくくできる

発展アイデア


次に読む