【学習】ターン制バトルで学ぶオブジェクト指向(5)ターン制バトル 〜同じ型で扱う・ポリモーフィズム〜
第4回までで Warrior と Mage は Character の派生 として整理できました。
ここがオブジェクト指向の 核心 です。
Warrior と Mage を、両方とも Character として扱う
そうすると、ターン制のループでは 「今攻撃しているのが戦士か魔導士か」 を都度 if で分けずに済みます。
今回の最小ゴール
Character型の変数・配列にWarriorとMageを入れる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 なのか
turnが0, 1, 2, 3, ...と増えるとき、turn % 2は0, 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つ)
- 最初から抽象化しなくていい … 第3回のように重複が見えてからでよい
- 継承は整理のための仕組み … 重複を減らし、ルールをはっきりさせる
GetPower()の1行が価値 … 種類が増えても、ループ側を書き換えにくくできる
発展アイデア
- 防御力・回復・状態異常を足す
List<Character>にして複数体を管理する(クラス気づき学習:List と相性がよい)- WinForms で RPG入門シリーズ の UI に載せる