ターン制バトルゲームから学ぶオブジェクト指向
C#の基礎、またオブジェクト指向からポリモーフィズムを学んだ方向けの学習用サンプルになります
ターン制の戦士と魔導士のバトルのイメージで眺めてください
コード
Character warrior = new Warrior(100, 20, 10);
Character mage = new Mage(80, 10, 15);
Character[] characters = { warrior, mage };
Console.WriteLine("バトル開始");
int turn = 0;
while (warrior.CurrentHP > 0 && mage.CurrentHP > 0)
{
    Console.WriteLine("ターン " + (turn + 1));
    Character attacker = characters[turn % 2];
    Character defender = characters[(turn + 1) % 2];
    int damage = attacker.Strength + attacker.GetAdditionalStat() - defender.Defense;
    defender.TakeDamage(damage);
    Console.WriteLine(attacker.GetType().Name + "が" + defender.GetType().Name + "に攻撃!" + damage + "のダメージ");
    Console.WriteLine(defender.GetType().Name + "のHPは、残り" + defender.CurrentHP + "です");
    turn++;
}
Console.WriteLine("バトル終了");
Console.WriteLine(warrior.CurrentHP > 0 ? "戦士の勝ち!" : "魔導士の勝ち!");
abstract class Character
{
    public int MaxHP { get; set; }
    public int CurrentHP { get; set; }
    public int Strength { get; set; }
    public int Defense { get; set; }
    public Character(int maxHP, int strength, int defense)
    {
        MaxHP = maxHP;
        CurrentHP = MaxHP;
        Strength = strength;
        Defense = defense;
    }
    public void TakeDamage(int damage)
    {
        CurrentHP -= damage;
        if (CurrentHP < 0)
        {
            CurrentHP = 0;
        }
    }
    public abstract int GetAdditionalStat();
}
class Warrior : Character
{
    public Warrior(int maxHP, int strength, int defense) : base(maxHP, strength, defense) { }
    public override int GetAdditionalStat()
    {
        return Strength / 2;
    }
}
class Mage : Character
{
    public Mage(int maxHP, int strength, int defense) : base(maxHP, strength, defense) { }
    public override int GetAdditionalStat()
    {
        return Defense / 2;
    }
}
実行結果
バトル開始
ターン 1
WarriorがMageに攻撃!15のダメージ
MageのHPは、残り65です
ターン 2
MageがWarriorに攻撃!7のダメージ
WarriorのHPは、残り93です
ターン 3
WarriorがMageに攻撃!15のダメージ
MageのHPは、残り50です
ターン 4
MageがWarriorに攻撃!7のダメージ
WarriorのHPは、残り86です
ターン 5
WarriorがMageに攻撃!15のダメージ
MageのHPは、残り35です
ターン 6
MageがWarriorに攻撃!7のダメージ
WarriorのHPは、残り79です
ターン 7
WarriorがMageに攻撃!15のダメージ
MageのHPは、残り20です
ターン 8
MageがWarriorに攻撃!7のダメージ
WarriorのHPは、残り72です
ターン 9
WarriorがMageに攻撃!15のダメージ
MageのHPは、残り5です
ターン 10
MageがWarriorに攻撃!7のダメージ
WarriorのHPは、残り65です
ターン 11
WarriorがMageに攻撃!15のダメージ
MageのHPは、残り0です
バトル終了
戦士の勝ち!
解説
全体の流れ
このコードは、C#によるターン制バトルシミュレーションのプログラムです。
- キャラクタークラスは抽象クラスとして定義され、キャラクターのステータス(MaxHP, CurrentHP, Strength, Defense)のプロパティと、ダメージを受ける(TakeDamage)、追加のスタットを取得する(GetAdditionalStat)ためのメソッドを保持しています。
 - WarriorクラスはCharacterクラスを継承し、Strength / 2を返すように追加ステータスを実装しています。
 - MageクラスはCharacterクラスを継承しており、Defense / 2を返す追加ステータスを実装しています。
 - Warrior変数には、MaxHP 100、Strength 20、Defense 10を持つWarriorクラスのインスタンスが格納されます。
 - mage変数にはMageクラスのインスタンスが格納され、MaxHP80、Strength10、Defense15となります。
 - 文字配列には戦士変数と魔道士変数が格納されます。
 - turn 変数はターン数を表します.
 - whileループの中では、戦士の現在HPと魔導士の現在HPがともに0以上の間、処理が継続されます。
- 毎ターン、attacker変数には攻撃側のキャラクターが、defender変数には防御側のキャラクターが格納されます。
 - ダメージ変数には、攻撃側の体力+追加ステータス-防御側の防御力が格納されます。
 - 防御側のCurrentHPはダメージ量だけ減少します。
 - コンソールには攻撃メッセージと各キャラクターのHPの状態が表示されます。
 - ターン変数が1つインクリメントされる。
 
 - whileループ終了後、勝者(戦士のCurrentHP>0)がコンソールに表示される。
 
コード解説
Character warrior = new Warrior(100, 20, 10);
Character mage = new Mage(80, 10, 15);
Character[] characters = { warrior, mage };
Console.WriteLine("バトル開始");
この部分は、2つのキャラクターオブジェクト(戦士、魔導士)を作成し、それらをキャラクター配列に格納しています。また、「バトル開始」というメッセージをコンソールに表示します。
Character warrior = new Warrior(100, 20, 10);:ここでは、Warriorクラスから新しい戦士オブジェクトを作成し、Character型の変数warriorに代入します。引数100, 20, 10は、戦士の最大HP、攻撃力、防御力を表します。Character mage = new Mage(80, 10, 15);:ここでは、Mageクラスから新しい魔法使いオブジェクトを作成し、Character型の変数mageに代入します。引数80, 10, 15は、魔法使いの最大HP、攻撃力、防御力を表します。Character[] characters = { warrior, mage };:ここでは、作成した戦士と魔法使いオブジェクトを含む配列を作成します。Console.WriteLine("バトル開始");:ここでは、「バトル開始」というメッセージをコンソールに表示します。
int turn = 0;
while (warrior.CurrentHP > 0 && mage.CurrentHP > 0)
{
    Console.WriteLine("ターン " + (turn + 1));
    Character attacker = characters[turn % 2];
    Character defender = characters[(turn + 1) % 2];
    int damage = attacker.Strength + attacker.GetAdditionalStat() - defender.Defense;
    defender.TakeDamage(damage);
    Console.WriteLine(attacker.GetType().Name + "が" + defender.GetType().Name + "に攻撃!" + damage + "のダメージ");
    Console.WriteLine(defender.GetType().Name + "のHPは、残り" + defender.CurrentHP + "です");
    turn++;
}
このコードは、ターン制のバトルシミュレーションを行っています。
- 変数
turnが宣言され、初期値は0となっています。 - 以下の処理が、
warriorキャラクターのCurrentHPが0以上、かつmageキャラクターのCurrentHPが0以上の間繰り返されます。- 現在のターン番号を表示します。
 - 攻撃するキャラクター
attackerと防御するキャラクターdefenderが決定されます。キャラクターの順番は、配列characters内のインデックスを切り替えて決定されます。 damage変数に攻撃力に加えて、追加のステータス値を引いた値から防御力を引いた値が代入されます。この計算は、attackerのStrengthプロパティとGetAdditionalStat()メソッド、defenderのDefenseプロパティを利用しています。defenderがdamage分のダメージを受けます。このダメージ処理は、TakeDamage()メソッドを利用しています。- 攻撃者と被害者のキャラクター名と、与えたダメージと、残りのHPが表示されます。
 turn変数に1を加えます。
 - どちらかのキャラクターのHPが0以下になったら、バトルは終了します。そして、生き残ったキャラクターの名前が表示されます。
 
Console.WriteLine("バトル終了");
Console.WriteLine(warrior.CurrentHP > 0 ? "戦士の勝ち!" : "魔導士の勝ち!");
このコードは、「バトル終了」という文字列を出力し、その後、warriorオブジェクトのCurrentHPが0より大きい場合に「戦士の勝ち!」、0以下の場合に「魔導士の勝ち!」という文字列を出力するものです。ここで、この文字列の出力結果は、勝者を示すものになります。
abstract class Character
{
    public int MaxHP { get; set; }
    public int CurrentHP { get; set; }
    public int Strength { get; set; }
    public int Defense { get; set; }
    public Character(int maxHP, int strength, int defense)
    {
        MaxHP = maxHP;
        CurrentHP = MaxHP;
        Strength = strength;
        Defense = defense;
    }
    public void TakeDamage(int damage)
    {
        CurrentHP -= damage;
        if (CurrentHP < 0)
        {
            CurrentHP = 0;
        }
    }
    public abstract int GetAdditionalStat();
}
このコードは、RPGゲームのキャラクターを表す抽象クラスCharacterを定義しています。
このクラスは、以下のフィールドを定義しています:
MaxHP: キャラクターの最大HPCurrentHP: キャラクターの現在のHPStrength: キャラクターの戦闘力Defense: キャラクターの防御力
また、以下のメソッドを定義しています:
TakeDamage: 与えられたダメージを受ける。現在のHPが0未満にならないように調整されます。GetAdditionalStat: 追加のステータス値を取得するための抽象メソッド。このメソッドは継承先でオーバーライドされます。
このクラスは抽象クラスであり、抽象メソッドを1つ持っています。抽象クラスは継承して使用することができ、継承先で抽象メソッドを実装する必要があります。
class Warrior : Character
{
    public Warrior(int maxHP, int strength, int defense) : base(maxHP, strength, defense) { }
    public override int GetAdditionalStat()
    {
        return Strength / 2;
    }
}
class Mage : Character
{
    public Mage(int maxHP, int strength, int defense) : base(maxHP, strength, defense) { }
    public override int GetAdditionalStat()
    {
        return Defense / 2;
    }
}
このコードは、「Warrior」クラスと「Mage」クラスを定義しています。これらのクラスは「Character」クラスを継承しています。「Character」クラスは抽象クラスであり、「MaxHP」、「CurrentHP」、「Strength」、「Defense」というプロパティを持っています。また、「TakeDamage」と「GetAdditionalStat」という抽象メソッドも定義されています。
「Warrior」クラスは「Character」クラスを継承しています。「Warrior」クラスは「MaxHP」、「Strength」、「Defense」というパラメータを受け取り、「Character」クラスのコンストラクタを呼び出して初期化します。「Warrior」クラスは「GetAdditionalStat」メソッドをオーバーライドして、「Strength」プロパティを2で割った値を返します。
「Mage」クラスも「Character」クラスを継承しています。「Mage」クラスは「MaxHP」、「Strength」、「Defense」というパラメータを受け取り、「Character」クラスのコンストラクタを呼び出して初期化します。「Mage」クラスは「GetAdditionalStat」メソッドをオーバーライドして、「Defense」プロパティを2で割った値を返します。






ディスカッション
コメント一覧
まだ、コメントがありません