0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オブジェクト指向って何?RPGで理解する超入門 (総合演習-RPGシステム構築)

0
Last updated at Posted at 2026-01-01

title_banner(1).png

この回で学ぶこと

所要時間

  • 記事を読むだけ: 約30分
  • コードを書いて実行: 約60〜90分
  • 応用問題まで挑戦: 約120分

前提知識

この回は 最終回 です!これまでに学んだ全ての知識を使います:

  • 第1回〜第6回: 変数、配列、クラス、コンストラクタ、カプセル化、参照型
  • 第7回: 継承の基礎(extends, super, オーバーライド)
  • 第8回: ポリモーフィズム(アップキャスト、ダウンキャスト、instanceof)
  • 第9回: 抽象クラスとインターフェース

学習目標

  1. 複数のクラスを組み合わせた大規模システムを設計できる
  2. オブジェクト指向の三本柱(カプセル化・継承・ポリモーフィズム)を実践できる
  3. 抽象クラスとインターフェースを適切に使い分けられる
  4. 実践的なRPGバトルシステムを完成させられる

はじめはコードが長く感じるかもしれません
この教材では、少しずつ「読めるようになる」ことを目標にしています

読めるようになると、すでにあるコードを安全に直したり
別のプログラムで使い回したりできるようになります

今回作るもの: RPGバトルシステム

最終回では、これまで学んだ全ての知識を使って 本格的なRPGバトルシステム を構築します!

システムの特徴

  • パーティー編成システム: 戦士・魔法使い・回復役を組み合わせる
  • ターン制バトル: プレイヤーと敵が交互に行動
  • スキルシステム: 通常攻撃・魔法・回復技を使い分ける
  • 装備システム: 武器と防具で能力を強化
  • 経験値・レベルアップシステム: 戦闘で成長する

1. システム全体の設計

まず、システム全体の構造を見てみましょう!

system_class_diagram_player_complete.png

クラス設計の全体像

抽象クラス層(共通の設計図)

  • Player: すべてのキャラクターの基礎
  • Skill: すべてのスキルの基礎
  • Equipment: すべての装備の基礎

具象クラス層(実際のキャラクター)

  • プレイヤー側: Warrior(戦士)、Mage(魔法使い)、Healer(回復役)
  • 敵側: Goblin(ゴブリン)、Orc(オーク)、Dragon(ドラゴン)

管理クラス層(システムの司令塔)

  • Party: パーティーを管理
  • BattleSystem: 戦闘全体を制御
  • Skill: スキル発動を管理

設計のポイント

概念 使い方 理由
抽象クラス Player, Skill, Equipment 共通のフィールド(HP、名前など)を持つため
継承 職業ごとにクラスを派生 コードの再利用と拡張が簡単
ポリモーフィズム Player[]で統一管理 パーティーや敵グループをまとめて扱える
インターフェース Combatable 「できること」を明確に定義

アプリケーション構成図

  • ファイル構成一覧
📂 RPGBattleSystem/
├── 📄 Main.java                  ← ゲーム起動(エントリーポイント)
├── 📄 BossBattle.java            ← ゲーム起動(エントリーポイント)※ボス戦
├── 📄 BattleSystem.java          ← バトル全体を管理
├── 📄 Party.java                 ← パーティー管理
├── 📄 Combatable.java            ← 戦闘可能なオブジェクトを表すインターフェース
├── 📄 Player.java                ← キャラクター基底クラス(抽象)
├── 📄 Warrior.java               ← 戦士クラス
├── 📄 Mage.java                  ← 魔法使いクラス
├── 📄 Healer.java                ← 僧侶クラス
├── 📄 Dragon.java                ← ドラゴンクラス
├── 📄 Goblin.java                ← ゴブリンクラス
├── 📄 Orc.java                   ← オーククラス
├── 📄 Skill.java                 ← スキル基底クラス(抽象)
├── 📄 Fireball.java              ← 魔法スキル
├── 📄 Heal.java                 ← 回復スキル
├── 📄 PowerSlash.java            ← 攻撃スキル
├── 📄 Equipment.java             ← 装備基底クラス(抽象)
├── 📄 Weapon.java                ← 武器クラス
└── 📄 Armor.java                 ← 防具クラス

💡 実務では?
今回は学習しやすいように、すべてのクラスを同じフォルダ(デフォルトパッケージ)に配置しています。
しかし、実際の業務では以下のようにパッケージで分類
することが多いです

📂 RPGBattleSystem
├── 📂 com.rpg.main
│   ├── 📄 Main.java                  ← ゲーム起動(エントリーポイント)
│   └── 📄 BossBattle.java            ← ゲーム起動(エントリーポイント)※ボス戦
├── 📂 com.rpg.battle
│   ├── 📄 BattleSystem.java          ← バトル全体を管理
│   └── 📄 Party.java                 ← パーティー管理
├── 📂 com.rpg.character
│   ├── 📄 Combatable.java            ← 戦闘可能なオブジェクトを表すインターフェース
│   ├── 📄 Player.java                ← キャラクター基底クラス(抽象)
│   ├── 📄 Warrior.java               ← 戦士クラス
│   ├── 📄 Mage.java                  ← 魔法使いクラス
│   ├── 📄 Healer.java                ← 僧侶クラス
│   ├── 📄 Dragon.java                ← ドラゴンクラス
│   ├── 📄 Goblin.java                ← ゴブリンクラス
│   └── 📄 Orc.java                   ← オーククラス
├── 📂 com.rpg.skill
│   ├── 📄 Skill.java                 ← スキル基底クラス(抽象)
│   ├── 📄 Fireball.java              ← 魔法スキル
│   ├── 📄 Heal.java                  ← 回復スキル
│   └── 📄 PowerSlash.java            ← 攻撃スキル
└── 📂 com.rpg.equipment
    ├── 📄 Equipment.java             ← 装備基底クラス(抽象)
    ├── 📄 Weapon.java                ← 武器クラス
    └── 📄 Armor.java                 ← 防具クラス

パッケージ分けのメリット

  • 役割ごとに整理されて見通しが良くなる
  • クラス名が重複してもパッケージで区別できる
  • 大規模プロジェクトでも管理しやすい

今後、より大きなプログラムを作るときは、ぜひパッケージ分けを意識してみてください!

1-1. 忙しい人のためにソースをおきました

📚GitHubサンプルコードはこちら

2. 装備システム

まずは装備システムを作成しましょう!
武器と防具を装備して能力を強化します!

  • 装備システムイメージ(実際のコードと少し異なります)

equipment_system.png

Equipmentクラス(抽象クラス)

Equipment.java
/**
 * RPGゲームの装備品を表す抽象クラス
 * 武器や防具などの装備品の基本となるクラス
 * 攻撃力や防御力のボーナスを提供する
 */
public abstract class Equipment {
    protected String name;        // 装備品の名前
    protected int attackBonus;    // 攻撃力ボーナス
    protected int defenseBonus;   // 防御力ボーナス
    
    /**
     * 装備品のコンストラクタ
     * 
     * @param name 装備品の名前
     * @param attackBonus 攻撃力ボーナス
     * @param defenseBonus 防御力ボーナス
     */
    public Equipment(String name, int attackBonus, int defenseBonus) {
        this.name = name;
        this.attackBonus = attackBonus;
        this.defenseBonus = defenseBonus;
    }
    
    /**
     * 装備品の詳細情報を表示する(各サブクラスで実装)
     */
    public abstract void showInfo();
    
    /**
     * 装備品の名前を取得
     * @return 装備品の名前
     */
    public String getName() { return name; }
    
    /**
     * 攻撃力ボーナスを取得
     * @return 攻撃力ボーナス値
     */
    public int getAttackBonus() { return attackBonus; }
    
    /**
     * 防御力ボーナスを取得
     * @return 防御力ボーナス値
     */
    public int getDefenseBonus() { return defenseBonus; }
}

Weaponクラス(武器)

Weapon.java
/**
 * 武器クラス
 * キャラクターの攻撃力を向上させる装備品
 * 剣、杖、弓などの武器を表す
 */
public class Weapon extends Equipment {
    
    /**
     * 武器のコンストラクタ
     * 武器は攻撃力のみを向上させる
     * 
     * @param name 武器の名前
     * @param attackBonus 攻撃力ボーナス
     */
    public Weapon(String name, int attackBonus) {
        super(name, attackBonus, 0);  // 武器は攻撃力のみ上昇
    }
    
    /**
     * 武器の詳細情報を表示
     */
    @Override
    public void showInfo() {
        System.out.println("┌─────────────────────────");
        System.out.println("│ 武器名: " + super.name);
        System.out.println("│ 攻撃力ボーナス: +" + super.attackBonus);
        System.out.println("│ 種類: 武器");
        System.out.println("└─────────────────────────");
    }
}

Armorクラス(防具)

Armor.java
/**
 * 防具クラス
 * キャラクターの防御力を向上させる装備品
 * 銃、盾、ヘルメットなどの防具を表す
 */
public class Armor extends Equipment {
    
    /**
     * 防具のコンストラクタ
     * 防具は防御力のみを向上させる
     * 
     * @param name 防具の名前
     * @param defenseBonus 防御力ボーナス
     */
    public Armor(String name, int defenseBonus) {
        super(name, 0, defenseBonus);  // 防具は防御力のみ上昇
    }
    
    /**
     * 防具の詳細情報を表示
     */
    @Override
    public void showInfo() {
        System.out.println("┌─────────────────────────");
        System.out.println("│ 防具名: " + super.name);
        System.out.println("│ 防御力ボーナス: +" + super.defenseBonus);
        System.out.println("│ 種類: 防具");
        System.out.println("└─────────────────────────");
    }
}

3. パーティー編成システム

つぎは冒険者のパーティーを作りましょう!

party_system.png

戦闘可能なオブジェクトを表すインターフェース

Combatableインターフェースを作成

Combatable.java
/**
 * 戦闘可能なオブジェクトを表すインターフェース
 * defaultメソッドで共通処理を提供
 */
public interface Combatable {
    /**
     * 攻撃力を取得する(実装必須)
     * @return 攻撃力
     */
    int getAttack();
    
    /**
     * 防御力を取得する(実装必須)
     * @return 防御力
     */
    int getDefense();
    
    /**
     * 名前を取得する(実装必須)
     * @return 名前
     */
    String getName();
    
    /**
     * 通常攻撃を行う(defaultメソッド)
     * @param target 攻撃対象
     */
    default void performAttack(Player target) {
        System.out.println(getName() + "の攻撃!");
        int damage = getAttack(); // 実装されたメソッドの呼び出し
        target.takeDamage(damage);
    }
    
    /**
     * 戦闘開始時のメッセージ(defaultメソッド)
     */
    default void battleCry() {
        System.out.println(getName() + "が戦闘態勢に入った!");
    }
    
    /**
     * クリティカル攻撃(defaultメソッド)
     * @param target 攻撃対象
     */
    default void criticalAttack(Player target) {
        System.out.println(getName() + "のクリティカル攻撃!");
        int damage = (int)(getAttack() * 1.5);
        target.takeDamage(damage);
    }
}

Playerクラス(抽象クラス)

Combatableインターフェースをimplementsする

Player.java
/**
 * RPGゲームのプレイヤーキャラクターを表す抽象クラス
 * 戦士、魔法使い、回復役などの基本となるクラス
 */
public abstract class Player implements Combatable {
    // 共通フィールド
    protected String name;      // 名前
    protected int maxHp;        // 最大HP
    protected int currentHp;    // 現在のHP
    protected int attack;       // 攻撃力
    protected int defense;      // 防御力
    protected int level;        // レベル
    protected int experience;   // 経験値
    protected Party party;      // 所属パーティ
    protected Weapon weapon;    // 装備中の武器
    protected Armor armor;      // 装備中の防具

    /**
     * プレイヤーキャラクターのコンストラクタ
     * 
     * @param name キャラクターの名前
     * @param maxHp 最大HP
     * @param attack 攻撃力
     * @param defense 防御力
     */
    public Player(String name, int maxHp, int attack, int defense) {
        this.name = name;
        this.maxHp = maxHp;
        this.currentHp = maxHp;  // 最初はHPが満タン
        this.attack = attack;
        this.defense = defense;
        this.level = 1;
        this.experience = 0;
    }

    // performAttack、battleCry、criticalAttackは
    // defaultメソッドなので実装不要(そのまま使える)

    /**
     * スキルを使用する(各職業で実装が異なる)
     * @param target スキルの対象となるプレイヤー
     */
    public abstract void useSkill(Player target);
    
    /**
     * 職業名を取得する(各職業で実装が異なる)
     * @return 職業名の文字列
     */
    public abstract String getRole(); 
    
    /**
     * ダメージを受ける処理
     * 防御力を考慮してダメージを計算し、HPを減らす
     * @param damage 受けるダメージ量
     */
    public void takeDamage(int damage) {
        int totalDefense = getDefense(); // 装備込みの防御力を使用
        int actualDamage = Math.max(1, damage - totalDefense);
        this.currentHp -= actualDamage;
        if (this.currentHp < 0) this.currentHp = 0;
        
        System.out.println(this.name + "は " + actualDamage + " のダメージを受けた!");
    }
    
    /**
     * HPを回復する処理
     * 最大HPを超えないように制限する
     * @param amount 回復するHP量
     */
    public void heal(int amount) {
        this.currentHp += amount;
        if (this.currentHp > this.maxHp) this.currentHp = this.maxHp;
        
        System.out.println(this.name + "は " + amount + " 回復した!");
    }
    
    /**
     * キャラクターが生きているかどうかを判定
     * @return 生きている場合true、戦闘不能の場合false
     */    
    public boolean isAlive() {
        return this.currentHp > 0;
    }
    
    /**
     * キャラクターのステータスを表示する
     */    
    public void displayStatus() {
        System.out.println("┌─────────────────────────");
        System.out.println("│ " + this.name + " [" + getRole() + "] Lv." + this.level);
        System.out.println("│ HP: " + this.currentHp + "/" + this.maxHp);
        System.out.println("│ 攻撃力: " + this.attack + " / 防御力: " + this.defense);
        System.out.println("│ 経験値: " + this.experience + " / " + getRequiredExp());
        System.out.println("└─────────────────────────");
    }
    
    /**
     * レベルアップに必要な経験値を計算
     * @return 次のレベルに必要な経験値
     */
    public int getRequiredExp() {
        return this.level * 100;
    }
    
    /**
     * 経験値を獲得し、レベルアップ判定を行う
     * @param exp 獲得する経験値
     */
    public void gainExperience(int exp) {
        this.experience += exp;
        System.out.println(this.name + "は " + exp + " の経験値を得た!");
        
        // レベルアップチェック
        while (this.experience >= getRequiredExp()) {
            levelUp();
        }
    }
    
    /**
     * レベルアップ処理(内部処理用)
     * ステータスを上昇させ、HPを全回復する
     */
    private void levelUp() {
        int requiredExp = getRequiredExp();  // レベルアップ前の必要経験値を保存
        this.level++;
        this.experience -= requiredExp;
        
        // ステータスアップ
        int hpUp = 20;
        int attackUp = 5;
        int defenseUp = 3;
        
        this.maxHp += hpUp;
        this.currentHp = this.maxHp;  // HP全回復
        this.attack += attackUp;
        this.defense += defenseUp;
        
        System.out.println("\n" + this.name + "はレベルアップした! (Lv." + this.level + ")");
        System.out.println("   最大HP +" + hpUp);
        System.out.println("   攻撃力 +" + attackUp);
        System.out.println("   防御力 +" + defenseUp + "\n");
    }
    
    /**
     * 武器を装備する
     * @param weapon 装備する武器
     */
    public void equipWeapon(Weapon weapon) {
        this.weapon = weapon;
        System.out.println(this.name + "は" + weapon.getName() + "を装備した!");
    }

    /**
     * 防具を装備する
     * @param armor 装備する防具
     */
    public void equipArmor(Armor armor) {
        this.armor = armor;
        System.out.println(this.name + "は" + armor.getName() + "を装備した!");
    }

    /**
     * 所属パーティを設定する
     * @param party 所属するパーティ
     */
    public void setParty(Party party) { this.party = party; }
    
    /**
     * 所属パーティを取得する
     * @return 所属しているパーティ
     */
    public Party getParty() { return party; }
    
    /**
     * キャラクターの名前を取得
     * @return キャラクターの名前
     */
    @Override
    public String getName() { return name; }
    
    /**
     * 現在のHPを取得
     * @return 現在のHP
     */
    public int getCurrentHp() { return currentHp; }
    
    /**
     * 最大HPを取得
     * @return 最大HP
     */
    public int getMaxHp() { return maxHp; }
    
    /**
     * 攻撃力を取得(装備、レベル込み)
     * @return 攻撃力
     */
    @Override
    public int getAttack() {
        int totalAttack = this.attack;
        
        // 装備ボーナス
        if (weapon != null) {
            totalAttack += weapon.getAttackBonus();
        }
        
        // レベルボーナス(レベル-1)×2
        totalAttack += (this.level - 1) * 2;
        
        return totalAttack;
    } 
    
    /**
     * 防御力を取得(装備、レベル込み)
     * @return 防御力
     */
    public int getDefense() {
        int totalDefense = this.defense;
        
        // 装備ボーナス
        if (armor != null) {
            totalDefense += armor.getDefenseBonus();
        }
        
        // レベルボーナス(レベル-1)×1
        totalDefense += (this.level - 1) * 1;
        
        return totalDefense;
    }
    
    /**
     * レベルを取得
     * @return 現在のレベル
     */
    public int getLevel() { return level; }
    
    /**
     * 経験値を取得
     * @return 現在の経験値
     */
    public int getExperience() { return experience; }
}

Warriorクラス(戦士)

Warrior.java
/**
 * 戦士キャラクタークラス
 * 高いHPと攻撃力を持ち、パワースラッシュで強力な攻撃を行う
 * パーティの盾役として活躍する
 */
public class Warrior extends Player {
    
    /**
     * 戦士のコンストラクタ
     * HP高め、攻撃力高めのバランスで初期化
     * 
     * @param name 戦士の名前
     */
    public Warrior(String name) {
        super(name, 150, 30, 15);  // HP高め、攻撃力高め
    }
    
    /**
     * 職業名を返す
     * @return "戦士"という文字列
     */
    @Override
    public String getRole() {
        return "戦士";
    }
    
    /**
     * パワースラッシュスキルを使用
     * 通常攻撃の1.5倍のダメージを与える強力な一撃
     * @param target 攻撃対象のプレイヤー
     */
    @Override
    public void useSkill(Player target) {
        // パワースラッシュ(強力な一撃)
        System.out.println(this.name + "の「パワースラッシュ」!");
        int damage = (int)(this.attack * 1.5);  // 攻撃力の1.5倍
        target.takeDamage(damage);
    }
    
    /**
     * 戦士専用の戦闘開始メッセージ(defaultメソッドをオーバーライド)
     */
    @Override
    public void battleCry() {
        System.out.println(getName() + ":\"正義の剣で悪を討つ!\"");
    }
}

Mageクラス(魔法使い)

Mage.java
/**
 * 魔法使いキャラクタークラス
 * HPは低いがMPを消費して強力な魔法攻撃を行う
 * ファイアボールで遠距離攻撃が得意
 */
public class Mage extends Player {
    private int maxMp;      // 最大MP
    private int currentMp;  // 現在のMP
    
    /**
     * 魔法使いのコンストラクタ
     * HP低め、攻撃力普通のバランスで初期化
     * 
     * @param name 魔法使いの名前
     */
    public Mage(String name) {
        super(name, 80, 15, 8);  // HP低め、攻撃力普通
        this.maxMp = 50;
        this.currentMp = 50;
    }
    
    /**
     * 職業名を返す
     * @return "魔法使い"という文字列
     */
    @Override
    public String getRole() {
        return "魔法使い";
    }
    
    /**
     * ファイアボールスキルを使用
     * MPが10以上ある場合のみ使用可能
     * 攻撃力に加えて魔法の固定ダメージを与える
     * @param target 攻撃対象のプレイヤー
     */
    @Override
    public void useSkill(Player target) {
        if (this.currentMp >= 10) {
            // ファイアボール(魔法攻撃)
            System.out.println(this.name + "の「ファイアボール」!");
            int damage = this.attack + 25;  // 魔法の固定ダメージ
            target.takeDamage(damage);
            this.currentMp -= 10;
            System.out.println("(MP: " + this.currentMp + "/" + this.maxMp + ")");
        } else {
            System.out.println(this.name + "のMPが足りない!");
        }
    }
    
    /**
     * 現在のMPを取得
     * @return 現在のMP
     */
    public int getCurrentMp() { return currentMp; }
    
    /**
     * 最大MPを取得
     * @return 最大MP
     */
    public int getMaxMp() { return maxMp; }
}

Healerクラス(回復役)

Healer.java
/**
 * 回復役キャラクタークラス
 * パーティメンバーのHPを回復するスキルを持つ
 * MPを消費してヒール魔法を使用する
 */
public class Healer extends Player {
    private int maxMp;      // 最大MP
    private int currentMp;  // 現在のMP
    
    /**
     * ヒーラーのコンストラクタ
     * HP普通、攻撃力低めのバランスで初期化
     * 
     * @param name ヒーラーの名前
     */
    public Healer(String name) {
        super(name, 100, 10, 12);  // HP普通、攻撃力低め
        this.maxMp = 60;
        this.currentMp = 60;
    }
    
    /**
     * 職業名を返す
     * @return "回復役"という文字列
     */
    @Override
    public String getRole() {
        return "回復役";
    }
    
    /**
     * ヒールスキルを使用してパーティメンバー全員を回復
     * MPが15以上ある場合のみ使用可能
     * 生きているパーティメンバー全員のHPを回復する
     * @param target 使用しないパラメータ(パーティ全員が対象のため)
     */
    @Override
    public void useSkill(Player target) {
        if (this.currentMp >= 15) {
            System.out.println(this.name + "の「ヒール」!");
            
            // パーティメンバー全員を回復
            if (this.party != null) {
                int healAmount = 40;
                Player[] members = this.party.getMembers();
                int memberCount = this.party.getMemberCount();
                
                for (int i = 0; i < memberCount; i++) {
                    if (members[i].isAlive()) {
                        members[i].heal(healAmount);
                    }
                }
            }
            
            this.currentMp -= 15;
            System.out.println("(MP: " + this.currentMp + "/" + this.maxMp + ")");
        } else {
            System.out.println(this.name + "のMPが足りない!");
        }
    }
    
    /**
     * 現在のMPを取得
     * @return 現在のMP
     */
    public int getCurrentMp() { return currentMp; }
    
    /**
     * 最大MPを取得
     * @return 最大MP
     */
    public int getMaxMp() { return maxMp; }
}

Partyクラス(パーティー管理)

Party.java
/**
 * RPGゲームのパーティ管理クラス
 * プレイヤーキャラクターや敵キャラクターのグループを管理する
 * メンバーの追加、状態確認、全滅判定などを行う
 */
public class Party {
    private Player[] members;   // パーティメンバーの配列
    private int memberCount;    // 現在のメンバー数
    
    /**
     * パーティのコンストラクタ
     * 指定された最大サイズでパーティを初期化
     * 
     * @param maxSize パーティの最大メンバー数
     */
    public Party(int maxSize) {
        this.members = new Player[maxSize];
        this.memberCount = 0;
    }
    
    /**
     * パーティにメンバーを追加する
     * メンバーにパーティ参照も自動設定される
     * 
     * @param character 追加するプレイヤーキャラクター
     */
    public void addMember(Player character) {
        if (memberCount < members.length) {
            members[memberCount] = character;
            character.setParty(this);  // パーティ参照を設定
            memberCount++;
            System.out.println("✅ " + character.getName() + "がパーティーに加わった!");
        } else {
            System.out.println("❌ パーティーは満員です!");
        }
    }
    
    /**
     * 生きているメンバーの数を数える
     * 
     * @return 生きているメンバーの数
     */
    public int getAliveCount() {
        int count = 0;
        for (int i = 0; i < memberCount; i++) {
            if (members[i].isAlive()) {
                count++;
            }
        }
        return count;
    }
    
    /**
     * パーティの全滅判定
     * 生きているメンバーが0人の場合にtrueを返す
     * 
     * @return 全滅している場合true、そうでなければfalse
     */
    public boolean isDefeated() {
        return getAliveCount() == 0;
    }
    
    /**
     * パーティ全体のステータスを表示する
     * 各メンバーの詳細情報を罫線で囲んで表示
     */
    public void displayStatus() {
        System.out.println("\n════════ パーティー情報 ════════");
        for (int i = 0; i < memberCount; i++) {
            members[i].displayStatus();
        }
        System.out.println("════════════════════════════════\n");
    }
    
    /**
     * パーティメンバーの配列を取得
     * @return メンバーの配列
     */
    public Player[] getMembers() { return members; }
    
    /**
     * 現在のメンバー数を取得
     * @return メンバー数
     */
    public int getMemberCount() { return memberCount; }
}

4. ターン制バトルシステム

次に、戦闘の流れを制御するシステムを作ります!

battle_flow.png

BattleSystemクラス

BattleSystem.java
import java.util.Scanner;

/**
 * RPGゲームのバトルシステムクラス
 * プレイヤーパーティと敵パーティの戦闘を管理する
 * ターン制バトルで、勝敗判定や経験値付与も行う
 */
public class BattleSystem {
    private Party playerParty;  // プレイヤーパーティ
    private Party enemyParty;   // 敵パーティ
    private int turnCount;      // ターン数
    
    /**
     * バトルシステムのコンストラクタ
     * プレイヤーパーティと敵パーティを設定してバトルを初期化
     * 
     * @param playerParty プレイヤーのパーティ
     * @param enemyParty 敵のパーティ
     */
    public BattleSystem(Party playerParty, Party enemyParty) {
        this.playerParty = playerParty;
        this.enemyParty = enemyParty;
        this.turnCount = 1;
    }
    
    /**
     * バトルを開始するメインメソッド
     * プレイヤーターンと敵ターンを交互に実行し、勝敗が決まるまで繰り返す
     */
    public void startBattle() {
        // try-with-resourcesでScannerを自動クローズ
        try (Scanner scanner = new Scanner(System.in)) {
            System.out.println("\n ════════════════════════ ");
            System.out.println("           バトル開始!");
            System.out.println(" ════════════════════════ \n");

            // 戦闘態勢にはいる
            doBattleCry(playerParty);
            doBattleCry(enemyParty);
            
            // バトルループ
            while (!isBattleOver()) {
                System.out.println("\n--- ターン " + turnCount + " ---\n");
                
                // プレイヤーターン
                playerTurn(scanner);
                if (enemyParty.isDefeated()) break;
                
                // 敵ターン
                enemyTurn();
                if (playerParty.isDefeated()) break;
                
                turnCount++;
            }
            
            // 勝敗判定
            displayResult();
        } // Scannerは自動的にclose()される
    }
    
    /**
     * 戦闘態勢にはいる
     * @param party
     */
    private void doBattleCry(Party party) {
    	for(Player p : party.getMembers()) {
    		p.battleCry();
    	}
    }
    
    /**
     * プレイヤーターンの処理
     * 各プレイヤーキャラクターの行動を選択し、実行する
     * 
     * @param scanner ユーザー入力用のScannerオブジェクト
     */
    private void playerTurn(Scanner scanner) {
        System.out.println("【プレイヤーのターン】");
        
        Player[] members = playerParty.getMembers();
        for (int i = 0; i < playerParty.getMemberCount(); i++) {
            Player character = members[i];
            
            if (!character.isAlive()) {
                System.out.println(character.getName() + "は戦闘不能...");
                continue;
            }
            
            System.out.println("\n" + character.getName() + "の行動:");
            System.out.println("1. 通常攻撃");
            System.out.println("2. スキル");
            System.out.print("選択 >> ");
            
            int choice = scanner.nextInt();
            
            // ターゲット選択
            Player target = selectTarget(enemyParty, scanner);
            if (target == null) continue;
            
            if (choice == 1) {
                // 通常攻撃
                normalAttack(character, target);
            } else if (choice == 2) {
                // スキル使用
                character.useSkill(target);
            }
            
            // 敵が全滅したらターン終了
            if (enemyParty.isDefeated()) break;
        }
    }
    
    /**
     * 敵ターンの処理
     * 敵キャラクターがランダムにプレイヤーを攻撃する
     */
    private void enemyTurn() {
        System.out.println("\n【敵のターン】");
        
        Player[] enemies = enemyParty.getMembers();
        for (int i = 0; i < enemyParty.getMemberCount(); i++) {
            Player enemy = enemies[i];
            
            if (!enemy.isAlive()) continue;
            
            // ランダムでプレイヤーを攻撃
            Player target = selectRandomAliveTarget(playerParty);
            if (target != null) {
                normalAttack(enemy, target);
            }
            
            // プレイヤーが全滅したらターン終了
            if (playerParty.isDefeated()) break;
        }
    }
    
    /**
     * 通常攻撃の処理
     * 攻撃者の攻撃力でターゲットにダメージを与える
     * 
     * @param character 攻撃するキャラクター
     * @param target 攻撃されるターゲット
     */
    private void normalAttack(Player character, Player target) {
        System.out.println(character.getName() + "の攻撃!");
        int damage = character.getAttack();
        target.takeDamage(damage);
    }
    
    /**
     * ターゲット選択の処理
     * ユーザーに攻撃対象を選択させる
     * 
     * @param party ターゲットを選択するパーティ
     * @param scanner ユーザー入力用のScannerオブジェクト
     * @return 選択されたプレイヤー、選択できなかった場合null
     */
    private Player selectTarget(Party party, Scanner scanner) {
        System.out.println("\nターゲットを選択:");
        Player[] members = party.getMembers();
        
        int aliveIndex = 0;
        for (int i = 0; i < party.getMemberCount(); i++) {
            if (members[i].isAlive()) {
                System.out.println((aliveIndex + 1) + ". " + members[i].getName() + 
                    " (HP: " + members[i].getCurrentHp() + "/" + members[i].getMaxHp() + ")");
                aliveIndex++;
            }
        }
        
        System.out.print("選択 >> ");
        int choice = scanner.nextInt() - 1;
        
        // 選択したキャラクターを返す
        aliveIndex = 0;
        for (int i = 0; i < party.getMemberCount(); i++) {
            if (members[i].isAlive()) {
                if (aliveIndex == choice) {
                    return members[i];
                }
                aliveIndex++;
            }
        }
        
        return null;
    }
    
    /**
     * ランダムなターゲットを選択する
     * 敵の攻撃時に使用し、生きているプレイヤーからランダムに選択
     * 
     * @param party ターゲットを選択するパーティ
     * @return ランダムに選択されたプレイヤー、生きているメンバーがいない場合null
     */
    private Player selectRandomAliveTarget(Party party) {
        Player[] members = party.getMembers();
        int[] aliveIndices = new int[party.getMemberCount()];
        int aliveCount = 0;
        
        for (int i = 0; i < party.getMemberCount(); i++) {
            if (members[i].isAlive()) {
                aliveIndices[aliveCount] = i;
                aliveCount++;
            }
        }
        
        if (aliveCount == 0) return null;
        
        int randomIndex = (int)(Math.random() * aliveCount);
        return members[aliveIndices[randomIndex]];
    }
    
    /**
     * バトル終了判定
     * どちらかのパーティが全滅した場合にtrueを返す
     * 
     * @return バトルが終了している場合true、続行中の場合false
     */
    private boolean isBattleOver() {
        return playerParty.isDefeated() || enemyParty.isDefeated();
    }
    
    /**
     * 勝敗結果を表示し、勝利時に経験値を付与する
     */
    private void displayResult() {
        System.out.println("\n ═══════════════════════════════════ ");
        if (enemyParty.isDefeated()) {
            System.out.println("            勝利! ");
            giveExperience();
        } else {
            System.out.println("            敗北... ");
        }
        System.out.println(" ═══════════════════════════════════ \n");
    }
    
    /**
     * 勝利時にプレイヤーパーティに経験値を付与する
     * 敵の数×50の経験値を生きているメンバーに付与
     */
    private void giveExperience() {
        int totalExp = enemyParty.getMemberCount() * 50;
        
        Player[] members = playerParty.getMembers();
        for (int i = 0; i < playerParty.getMemberCount(); i++) {
            if (members[i].isAlive()) {
                members[i].gainExperience(totalExp);
            }
        }
    }
}

5. スキルシステム

キャラクターごとに異なるスキルを実装します!

skill_system.png

Skillクラス(抽象クラス)

Skill.java
/**
 * RPGゲームのスキルを表す抽象クラス
 * 回復、攻撃、補助などの様々なスキルの基本となるクラス
 * MPコストや効果の実行を管理する
 */
public abstract class Skill {
    protected String name;          // スキル名
    protected int mpCost;           // MPコスト
    protected String description;   // スキルの説明
    
    /**
     * スキルのコンストラクタ
     * 
     * @param name スキルの名前
     * @param mpCost 使用に必要なMP
     * @param description スキルの説明文
     */
    public Skill(String name, int mpCost, String description) {
        this.name = name;
        this.mpCost = mpCost;
        this.description = description;
    }
    
    /**
     * スキルの効果を実行する(各スキルで実装が異なる)
     * 
     * @param user スキルを使用するプレイヤー
     * @param target スキルの対象となるプレイヤー
     */
    public abstract void execute(Player user, Player target);
    
    /**
     * スキル名を取得
     * 
     * @return スキルの名前
     */
    public String getName() { return name; }
    
    /**
     * MPコストを取得
     * 
     * @return 使用に必要なMP
     */
    public int getMpCost() { return mpCost; }
    
    /**
     * スキルの説明を取得
     * 
     * @return スキルの説明文
     */
    public String getDescription() { return description; }
}

PowerSlashスキル(戦士用)

PowerSlash.java
/**
 * パワースラッシュスキルクラス
 * 戦士が使用する強力な物理攻撃スキル
 * 通常攻撃よりも強いダメージを与える
 */
public class PowerSlash extends Skill {
    
    /**
     * パワースラッシュスキルのコンストラクタ
     * MPコストは0で、いつでも使用可能
     */
    public PowerSlash() {
        super("パワースラッシュ", 0, "攻撃力の1.5倍のダメージを与える");
    }
    
    /**
     * パワースラッシュスキルの効果を実行
     * 使用者の攻撃力の1.5倍のダメージを与える
     * 
     * @param user スキルを使用するプレイヤー
     * @param target 攻撃対象のプレイヤー
     */
    @Override
    public void execute(Player user, Player target) {
        System.out.println(user.getName() + "の「" + this.name + "」!");
        int damage = (int)(user.getAttack() * 1.5);
        target.takeDamage(damage);
    }
}

Fireballスキル(魔法使い用)

Fireball.java
/**
 * Fireballスキル(魔法使い用)
 */
public class Fireball extends Skill {
    
    public Fireball() {
        super("ファイアボール", 10, "炎の魔法で敵を攻撃する");
    }
    
    @Override
    public void execute(Player user, Player target) {
        System.out.println(user.getName() + "の「" + this.name + "」!");
        int damage = user.getAttack() + 25;
        target.takeDamage(damage);
    }
}

Healスキル(回復役用)

/**
 * ヒールスキルクラス
 * 回復役が使用する基本的な回復スキル
 * 味方のHPを回復させる効果を持つ
 */
public class Heal extends Skill {
    
    /**
     * ヒールスキルのコンストラクタ
     * スキル名、MPコスト、説明を設定する
     */
    public Heal() {
        super("ヒール", 15, "味方1人のHPを回復する");
    }
    
    /**
     * ヒールスキルの効果を実行
     * ターゲットのHPを固定値で回復させる
     * 
     * @param user スキルを使用するプレイヤー
     * @param target 回復対象のプレイヤー
     */
    @Override
    public void execute(Player user, Player target) {
        System.out.println(user.getName() + "の「" + this.name + "」!");
        int healAmount = 40;
        target.heal(healAmount);
    }
}

6. 経験値・レベルアップシステム

戦闘で経験値を得て成長します!

level_up_system.png

Playerクラスにメソッド追加

    // Playerクラスに以下を追加

    /**
     * 経験値を獲得し、レベルアップ判定を行う
     * 
     * @param exp 獲得する経験値
     */
    public void gainExperience(int exp) {
        this.experience += exp;
        System.out.println(this.name + "は " + exp + " の経験値を得た!");
        
        // レベルアップチェック
        while (this.experience >= getRequiredExp()) {
            levelUp();
        }
    }

    /**
     * レベルアップ処理(内部処理用)
     * ステータスを上昇させ、HPを全回復する
     */
    private void levelUp() {
        int requiredExp = getRequiredExp();  // レベルアップ前の必要経験値を保存
        this.level++;
        this.experience -= requiredExp;
        
        // ステータスアップ
        int hpUp = 20;
        int attackUp = 5;
        int defenseUp = 3;
        
        this.maxHp += hpUp;
        this.currentHp = this.maxHp;  // HP全回復
        this.attack += attackUp;
        this.defense += defenseUp;
        
        System.out.println("\n" + this.name + "はレベルアップした! (Lv." + this.level + ")");
        System.out.println("   最大HP +" + hpUp);
        System.out.println("   攻撃力 +" + attackUp);
        System.out.println("   防御力 +" + defenseUp + "\n");
    }

7. クラス継承ツリー全体図

これまでのクラスの関係性を整理しましょう!

Player (抽象クラス)
├── Warrior (戦士)
├── Mage (魔法使い)
├── Healer (回復役)
├── Goblin (ゴブリン)      ← 実践問題で作成
├── Orc (オーク)           ← 実践問題で作成
└── Dragon (ドラゴン)      ← 実践問題で作成

Skill (抽象クラス)
├── PowerSlash (パワースラッシュ)
├── Fireball (ファイアボール)
└── Heal (ヒール)

Equipment (抽象クラス)
├── Weapon (武器)
└── Armor (防具)

8. 実践問題:バトルシミュレーション

それでは、実際にバトルシステムを動かしてみましょう!

問題: 敵クラスを作成し、バトルをシミュレートせよ

以下の手順で、完全なバトルシステムを完成させてください:

  1. Goblinクラスを作成する(HP: 60, 攻撃: 15, 防御: 5)
  2. Orcクラスを作成する(HP: 100, 攻撃: 25, 防御: 10)
  3. Mainクラスでパーティーを編成し、バトルを実行する
解答を見る

Goblinクラス

Goblin.java
/**
 * ゴブリンの敵キャラクタークラス
 * 体力、攻撃力、防御力が低い初心者向けの敵
 * 特殊スキルは持たず、体当たりで攻撃する
 */
public class Goblin extends Player {
    
    /**
     * ゴブリンのコンストラクタ
     * 低いステータスで初期化される弱い敵
     * 
     * @param name ゴブリンの名前
     */
    public Goblin(String name) {
        super(name, 60, 15, 5);
    }
    
    /**
     * 敵の種族名を返す
     * 
     * @return "ゴブリン"という文字列
     */
    @Override
    public String getRole() {
        return "ゴブリン";
    }
    
    /**
     * ゴブリンの攻撃スキル
     * 特殊な能力はなく、通常攻撃と同じダメージの体当たり
     * 
     * @param target 攻撃対象のプレイヤー
     */
    @Override
    public void useSkill(Player target) {
        // ゴブリンは通常攻撃のみ
        System.out.println(this.name + "の体当たり!");
        int damage = this.attack;
        target.takeDamage(damage);
    }
    
    /**
     * ゴブリン専用の戦闘開始メッセージ
     */
    @Override
    public void battleCry() {
        System.out.println(getName() + ":\"ギャー!人間め!\"");
    }
}

Orcクラス

Orc.java
/**
 * オークの敵キャラクタークラス
 * ゴブリンよりも強い中級の敵キャラクター
 * 大振り攻撃で通常よりも強いダメージを与える
 */
public class Orc extends Player {
    
    /**
     * オークのコンストラクタ
     * ゴブリンよりも高いステータスで初期化
     * 
     * @param name オークの名前
     */
    public Orc(String name) {
        super(name, 100, 25, 10);
    }
    
    /**
     * 敵の種族名を返す
     * 
     * @return "オーク"という文字列
     */
    @Override
    public String getRole() {
        return "オーク";
    }
    
    /**
     * オークの大振り攻撃スキル
     * 通常攻撃の1.3倍のダメージを与える強力な一撃
     * 
     * @param target 攻撃対象のプレイヤー
     */
    @Override
    public void useSkill(Player target) {
        // 強力な一撃
        System.out.println(this.name + "の大振り攻撃!");
        int damage = (int)(this.attack * 1.3);
        target.takeDamage(damage);
    }
}

Mainクラス(バトル実行)

/**
 * RPGバトルシステムのメインクラス
 * ゲームのエントリーポイントとなるクラス
 * プレイヤーパーティと敵パーティを作成し、バトルを開始する
 */
public class Main {
    public static void main(String[] args) {
        System.out.println("═══════════════════════════════════");
        System.out.println("   Java Quest - RPGバトルシステム");
        System.out.println("═══════════════════════════════════\n");
        
        // プレイヤーパーティー作成
        Party playerParty = new Party(3);
        
        // キャラクター作成
        Warrior warrior = new Warrior("アレン");
        Mage mage = new Mage("リリア");
        Healer healer = new Healer("セレナ");
        
        // パーティーに追加
        playerParty.addMember(warrior);
        playerParty.addMember(mage);
        playerParty.addMember(healer);
        
        System.out.println();
        
        // 敵パーティー作成
        Party enemyParty = new Party(2);
        enemyParty.addMember(new Goblin("ゴブリンA"));
        enemyParty.addMember(new Orc("オークB"));
        
        System.out.println();
        
        // 初期ステータス表示
        playerParty.displayStatus();
        
        // バトル開始
        BattleSystem battle = new BattleSystem(playerParty, enemyParty);
        battle.startBattle();
    }
}

実行結果(例)

══════════════════════════════
   Java Quest - RPGバトルシステム
══════════════════════════════

✅ アレンがパーティーに加わった!
✅ リリアがパーティーに加わった!
✅ セレナがパーティーに加わった!

✅ ゴブリンAがパーティーに加わった!
✅ オークBがパーティーに加わった!


════════ パーティー情報 ════════
┌─────────────────────────
│ アレン [戦士] Lv.1
│ HP: 150/150
│ 攻撃力: 30 / 防御力: 15
│ 経験値: 0 / 100
└─────────────────────────
┌─────────────────────────
│ リリア [魔法使い] Lv.1
│ HP: 80/80
│ 攻撃力: 15 / 防御力: 8
│ 経験値: 0 / 100
└─────────────────────────
┌─────────────────────────
│ セレナ [回復役] Lv.1
│ HP: 100/100
│ 攻撃力: 10 / 防御力: 12
│ 経験値: 0 / 100
└─────────────────────────
════════════════════════


 ════════════════════════ 
           バトル開始!
 ════════════════════════ 

アレン:"正義の剣で悪を討つ!"
リリアが戦闘態勢に入った!
セレナが戦闘態勢に入った!
ゴブリンA:"ギャー!人間め!"
オークBが戦闘態勢に入った!

--- ターン 1 ---

【プレイヤーのターン】

アレンの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. ゴブリンA (HP: 60/60)
2. オークB (HP: 100/100)
選択 >> 1
アレンの「パワースラッシュ」!
ゴブリンAは 40 のダメージを受けた!

リリアの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. ゴブリンA (HP: 20/60)
2. オークB (HP: 100/100)
選択 >> 2
リリアの「ファイアボール」!
オークBは 30 のダメージを受けた!
(MP: 40/50)

セレナの行動:
1. 通常攻撃
2. スキル
選択 >> 1

ターゲットを選択:
1. ゴブリンA (HP: 20/60)
2. オークB (HP: 70/100)
選択 >> 1
セレナの攻撃!
ゴブリンAは 5 のダメージを受けた!

【敵のターン】
ゴブリンAの攻撃!
セレナは 3 のダメージを受けた!
オークBの攻撃!
アレンは 10 のダメージを受けた!

--- ターン 2 ---

【プレイヤーのターン】

アレンの行動:
1. 通常攻撃
2. スキル
選択 >> 1

ターゲットを選択:
1. ゴブリンA (HP: 15/60)
2. オークB (HP: 70/100)
選択 >> 1
アレンの攻撃!
ゴブリンAは 25 のダメージを受けた!

リリアの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. オークB (HP: 70/100)
選択 >> 1
リリアの「ファイアボール」!
オークBは 30 のダメージを受けた!
(MP: 30/50)

セレナの行動:
1. 通常攻撃
2. スキル
選択 >> 1

ターゲットを選択:
1. オークB (HP: 40/100)
選択 >> 1
セレナの攻撃!
オークBは 1 のダメージを受けた!

【敵のターン】
オークBの攻撃!
アレンは 10 のダメージを受けた!

--- ターン 3 ---

【プレイヤーのターン】

アレンの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. オークB (HP: 39/100)
選択 >> 1
アレンの「パワースラッシュ」!
オークBは 35 のダメージを受けた!

リリアの行動:
1. 通常攻撃
2. スキル
選択 >> 1

ターゲットを選択:
1. オークB (HP: 4/100)
選択 >> 1
リリアの攻撃!
オークBは 5 のダメージを受けた!

 ═══════════════════════════════════ 
            勝利! 
アレンは 100 の経験値を得た!

アレンはレベルアップした! (Lv.2)
   最大HP +20
   攻撃力 +5
   防御力 +3

リリアは 100 の経験値を得た!

リリアはレベルアップした! (Lv.2)
   最大HP +20
   攻撃力 +5
   防御力 +3

セレナは 100 の経験値を得た!

セレナはレベルアップした! (Lv.2)
   最大HP +20
   攻撃力 +5
   防御力 +3

 ═══════════════════════════════════ 

9. 応用問題:ボス戦を実装しよう!

問題: キャラクターに武器と防具を装備せよ

以下の仕様で装備してください

仕様(武器)

  • 勇者: 武器名 "鉄の剣", 攻撃力 15
  • 魔法使い: 武器名 "魔法のローブ", 攻撃力 8
  • 回復役: 武器名 "癒しの杖", 攻撃力 5

仕様(防具)

  • 勇者: 防具名 "プレートアーマ", 防御力 10
  • 魔法使い: 防具名 "魔法の杖", 防御力 3
  • 回復役: 防具名 "レザーアーマー", 防御力 5

問題: Dragonクラスを作成し、強力なボス戦を実装せよ

以下の仕様でドラゴンを実装してください

仕様

  • HP: 300
  • 攻撃力: 40
  • 防御力: 20
  • スキル: 「火炎ブレス」(全体攻撃、ダメージ30)
  • ダメージを受ける処理: HPが30%以下の場合、1度だけ「火炎ブレス」を発動
解答を見る
Dragon.java
/**
 * ドラゴンの敵キャラクタークラス
 * 非常に強力なボスキャラクターで、高いHPと攻撃力を持つ
 * 火炎ブレスで単体攻撃や全体攻撃を行う
 */
public class Dragon extends Player {
    private boolean breathFireUsed = false; // 火炎ブレス使用フラグ
    private Party enemyParty; // 攻撃対象のパーティ
  
    /**
     * ドラゴンのコンストラクタ
     * 非常に高いステータスで初期化される強敵
     * 
     * @param name ドラゴンの名前
     */
    public Dragon(String name) {
        super(name, 300, 40, 20);
    }
    
    /**
     * 敵の種族名を返す
     * 
     * @return "ドラゴン"という文字列
     */
    @Override
    public String getRole() {
        return "ドラゴン";
    }
    
    /**
     * ドラゴンの火炎ブレススキル(全体攻撃)
     * パーティ全員に30ダメージを与える
     * 
     * @param target 攻撃対象のプレイヤー(パーティ取得用)
     */
    @Override
    public void useSkill(Player target) {
        if (target.getParty() != null) {
            breathFire(target.getParty());
        }
    }
        
    /**
     * 攻撃対象のパーティを設定
     * @param enemyParty 攻撃対象のパーティ
     */
    public void setEnemyParty(Party enemyParty) {
        this.enemyParty = enemyParty;
    }
    
    /**
     * ダメージを受ける処理(オーバーライド)
     * HPが30%以下になったら火炎ブレスを自動発動
     */
    @Override
    public void takeDamage(int damage) {
        super.takeDamage(damage);
        
        // HPが30%以下かつ未使用の場合、火炎ブレスを発動
        if (!breathFireUsed && currentHp <= maxHp * 0.3 && enemyParty != null) {
            breathFireUsed = true;
            System.out.println(this.name + "は絶体絶命のピンチになった!");
            breathFire(enemyParty);
        }
    }
    
    /**
     * 全体攻撃用の火炎ブレス(特別メソッド)
     * パーティ全員に30ダメージを与える危険な攻撃
     * ボス戦での特殊攻撃として使用
     * 
     * @param party 攻撃対象のパーティ
     */
    public void breathFire(Party party) {
        System.out.println(this.name + "の「火炎ブレス」! (全体攻撃)");
        Player[] members = party.getMembers();
        for (int i = 0; i < party.getMemberCount(); i++) {
            if (members[i].isAlive()) {
                members[i].takeDamage(30);
                System.out.println(members[i].getName() + " HP: " + members[i].getCurrentHp() + "/" + members[i].getMaxHp());
            }
        }
    }
}

ボス戦のメイン処理

BossBattle.java
/**
 * RPGバトルシステムのボス戦クラス
 * レベル3に成長した勇者たちが古代竜バハムートと戦う最終決戦
 * 装備を装着した強化パーティでドラゴン討伐に挑む
 */
public class BossBattle {
	
    /**
     * ボス戦のメインメソッド
     * レベル3の勇者パーティを作成し、装備を装着させてドラゴンとの最終決戦を開始する
     * ゲームのクライマックスとなるボス戦を実行
     * 
     * @param args コマンドライン引数(使用しない)
     */
    public static void main(String[] args) {
        System.out.println("═════════════════════════");
        System.out.println("      最終決戦 - ドラゴン討伐");
        System.out.println("═════════════════════════\n");
        
        // レベル3のパーティー(強化済み)
        Party playerParty = new Party(3);
        Player warrior = new Warrior("アレン");
        warrior.gainExperience(300);  // Lv.3まで成長
        
        Player mage = new Mage("リリア");
        mage.gainExperience(300);
        
        Player healer = new Healer("セレナ");
        healer.gainExperience(300);

        // 装備品作成
        // 武器
        Weapon ironSword = new Weapon("鉄の剣", 15);
        Weapon magicStaff = new Weapon("魔法の杖", 8);
        Weapon healingStaff = new Weapon("癒しの杖", 5);
        
        // 防具
        Armor plateArmor = new Armor("プレートアーマー", 10);
        Armor magicRobe = new Armor("魔法のローブ", 3);
        Armor leatherArmor = new Armor("レザーアーマー", 5);
        
        // 装備させる
        warrior.equipWeapon(ironSword);
        warrior.equipArmor(plateArmor);
        
        mage.equipWeapon(magicStaff);
        mage.equipArmor(magicRobe);
        
        healer.equipWeapon(healingStaff);
        healer.equipArmor(leatherArmor);
        
        System.out.println();
        
        // パーティーに追加
        playerParty.addMember(warrior);
        playerParty.addMember(mage);
        playerParty.addMember(healer);
        
        // ボス登場
        Party bossParty = new Party(1);
        Dragon dragon = new Dragon("古代竜バハムート");
        dragon.setEnemyParty(playerParty); // 攻撃対象のパーティを設定
        bossParty.addMember(dragon);
        
        System.out.println();
        
        // ボス戦開始
        BattleSystem bossBattle = new BattleSystem(playerParty, bossParty);
        bossBattle.startBattle();
        
        System.out.println("\nおめでとうございます!");
        System.out.println("Java Questの全ての試練を乗り越えました!");
    }
}

実行結果の例:

═════════════════════════
      最終決戦 - ドラゴン討伐
═════════════════════════

アレンは 300 の経験値を得た!

アレンはレベルアップした! (Lv.2)
   最大HP +20
   攻撃力 +5
   防御力 +3


アレンはレベルアップした! (Lv.3)
   最大HP +20
   攻撃力 +5
   防御力 +3

リリアは 300 の経験値を得た!

リリアはレベルアップした! (Lv.2)
   最大HP +20
   攻撃力 +5
   防御力 +3


リリアはレベルアップした! (Lv.3)
   最大HP +20
   攻撃力 +5
   防御力 +3

セレナは 300 の経験値を得た!

セレナはレベルアップした! (Lv.2)
   最大HP +20
   攻撃力 +5
   防御力 +3


セレナはレベルアップした! (Lv.3)
   最大HP +20
   攻撃力 +5
   防御力 +3

アレンは鉄の剣を装備した!
アレンはプレートアーマーを装備した!
リリアは魔法の杖を装備した!
リリアは魔法のローブを装備した!
セレナは癒しの杖を装備した!
セレナはレザーアーマーを装備した!

✅ アレンがパーティーに加わった!
✅ リリアがパーティーに加わった!
✅ セレナがパーティーに加わった!
✅ 古代竜バハムートがパーティーに加わった!


 ════════════════════════ 
           バトル開始!
 ════════════════════════ 

アレン:"正義の剣で悪を討つ!"
リリアが戦闘態勢に入った!
セレナが戦闘態勢に入った!
古代竜バハムートが戦闘態勢に入った!

--- ターン 1 ---

【プレイヤーのターン】

アレンの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. 古代竜バハムート (HP: 300/300)
選択 >> 1
アレンの「パワースラッシュ」!
古代竜バハムートは 40 のダメージを受けた!

リリアの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. 古代竜バハムート (HP: 260/300)
選択 >> 1
リリアの「ファイアボール」!
古代竜バハムートは 30 のダメージを受けた!
(MP: 40/50)

セレナの行動:
1. 通常攻撃
2. スキル
選択 >> 1

ターゲットを選択:
1. 古代竜バハムート (HP: 230/300)
選択 >> 1
セレナの攻撃!
古代竜バハムートは 9 のダメージを受けた!

【敵のターン】
古代竜バハムートの攻撃!
アレンは 7 のダメージを受けた!

--- ターン 2 ---

【プレイヤーのターン】

アレンの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. 古代竜バハムート (HP: 221/300)
選択 >> 1
アレンの「パワースラッシュ」!
古代竜バハムートは 40 のダメージを受けた!

リリアの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. 古代竜バハムート (HP: 181/300)
選択 >> 1
リリアの「ファイアボール」!
古代竜バハムートは 30 のダメージを受けた!
(MP: 30/50)

セレナの行動:
1. 通常攻撃
2. スキル
選択 >> 1

ターゲットを選択:
1. 古代竜バハムート (HP: 151/300)
選択 >> 1
セレナの攻撃!
古代竜バハムートは 9 のダメージを受けた!

【敵のターン】
古代竜バハムートの攻撃!
アレンは 7 のダメージを受けた!

--- ターン 3 ---

【プレイヤーのターン】

アレンの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. 古代竜バハムート (HP: 142/300)
選択 >> 1
アレンの「パワースラッシュ」!
古代竜バハムートは 40 のダメージを受けた!

リリアの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. 古代竜バハムート (HP: 102/300)
選択 >> 1
リリアの「ファイアボール」!
古代竜バハムートは 30 のダメージを受けた!
古代竜バハムートは絶体絶命のピンチになった!
古代竜バハムートの「火炎ブレス」! (全体攻撃)
アレンは 39 のダメージを受けた!
アレン HP: 137/190
リリアは 53 のダメージを受けた!
リリア HP: 67/120
セレナは 47 のダメージを受けた!
セレナ HP: 93/140
(MP: 20/50)

セレナの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. 古代竜バハムート (HP: 72/300)
選択 >> 1
セレナの「ヒール」!
アレンは 40 回復した!
リリアは 40 回復した!
セレナは 40 回復した!
(MP: 45/60)

【敵のターン】
古代竜バハムートの攻撃!
リリアは 21 のダメージを受けた!

--- ターン 4 ---

【プレイヤーのターン】

アレンの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. 古代竜バハムート (HP: 72/300)
選択 >> 1
アレンの「パワースラッシュ」!
古代竜バハムートは 40 のダメージを受けた!

リリアの行動:
1. 通常攻撃
2. スキル
選択 >> 2

ターゲットを選択:
1. 古代竜バハムート (HP: 32/300)
選択 >> 1
リリアの「ファイアボール」!
古代竜バハムートは 30 のダメージを受けた!
(MP: 10/50)

セレナの行動:
1. 通常攻撃
2. スキル
選択 >> 1

ターゲットを選択:
1. 古代竜バハムート (HP: 2/300)
選択 >> 1
セレナの攻撃!
古代竜バハムートは 9 のダメージを受けた!

 ═══════════════════════════════════ 
            勝利! 
アレンは 50 の経験値を得た!
リリアは 50 の経験値を得た!
セレナは 50 の経験値を得た!
 ═══════════════════════════════════ 


おめでとうございます!
Java Questの全ての試練を乗り越えました!

10. 補足:設計パターンとOOP総復習

このシステムで使った設計パターン

パターン名 使用箇所 目的
Template Method Playerクラス 共通処理を親クラスで実装、具体的な動作は子クラスで定義
Strategy Skillクラス スキルの効果をオブジェクトとして扱い、実行時に切り替え
Factory パーティー作成 オブジェクトの生成を統一的に管理
Composite Partyクラス 複数のキャラクターをまとめて扱う

オブジェクト指向の三本柱 - 完全マスター!

カプセル化(第5回)

// フィールドをprivateで保護
private int currentHp;

// ゲッター/セッターで制御
public int getCurrentHp() { return currentHp; }

使用例: HPの直接書き換えを防ぎ、不正な値を防止

継承(第7回)

// 共通部分を親クラスに集約
public abstract class Adventurer { ... }

// 専門的な機能を子クラスで追加
public class Warrior extends Adventurer { ... }

使用例: コードの再利用とクラスの拡張

ポリモーフィズム(第8回)

// 親クラス型の配列で統一管理
Adventurer[] members = new Adventurer[3];
members[0] = new Warrior("アレン");
members[1] = new Mage("リナ");
members[2] = new Healer("ユイ");

// まとめてループ処理
for (Adventurer user : members) {
    user.useSkill(target);  // 各クラスの実装が呼ばれる
}

使用例: 異なるクラスを同じ型で扱い、柔軟な処理


summary_finale(1).png

あなたが習得したスキル

基礎編(第1回〜第6回)

  • 変数とデータ型
  • 配列とループ
  • クラスとオブジェクト
  • コンストラクタ
  • カプセル化
  • 参照型の理解

OOP三本柱(第7回〜第9回)

  • 継承(extends, super, オーバーライド)
  • ポリモーフィズム(アップキャスト、ダウンキャスト、instanceof)
  • 抽象クラスとインターフェース

実践編(第10回)

  • 大規模システムの設計
  • 複数クラスの連携
  • 設計パターンの活用
  • 本格的なRPGシステムの構築

これからの学習へ

Java Questを完走したあなたは、もう オブジェクト指向プログラミングの基礎 をマスターしています!

次のステップ

  1. コレクション(ArrayList, HashMap) を学ぶ
  2. 例外処理(try-catch) を理解する
  3. ファイル入出力 でセーブ機能を作る
  4. GUIプログラミング でビジュアル化する
  5. データベース接続 でデータを永続化する

おすすめの発展課題

  • 装備システムの拡張: 装備の付け外し機能を実装
  • アイテムシステム: ポーション、エリクサーなどを追加
  • ダンジョン探索: マップ移動とランダムエンカウント
  • セーブ/ロード機能: ファイルにデータを保存
  • GUI化: ビジュアルなバトル画面を作成

よくある質問(FAQ)

Q1. Partyクラスで配列を使う理由は?

A: この段階ではシンプルさを重視しています。
実践ではArrayList<Player>を使うと、サイズを気にせず追加・削除ができます!

// 発展: ArrayListを使った実装
import java.util.ArrayList;

public class Party {
    private ArrayList<Player> members;
    
    public Party() {
        this.members = new ArrayList<>();
    }
    
    public void addMember(Player character) {
        members.add(character);  // サイズ制限なし!
    }
}

Q2. BattleSystemが複雑すぎない?

A: 実際のゲーム開発では、もっと細かく分割します:

  • TurnManager: ターン管理
  • ActionResolver: 行動の実行
  • DamageCalculator: ダメージ計算
  • BattleUI: 画面表示

今回は学習用に1クラスにまとめていますが、役割ごとに分けるのが理想です!

Q3. レベルアップの計算式はどう決める?

A: 今回は簡単にlevel * 100にしましたが、実際のゲームでは:

// 指数関数的な成長(だんだん必要経験値が増える)
public int getRequiredExp() {
    return (int)(100 * Math.pow(level, 1.5));
}

このように調整すると、後半ほど成長が遅くなるリアルな設計になります!

Q4. このシステムをもっと拡張するには?

A: たくさんのアイデアがあります!

拡張案 実装方法
状態異常 Statusクラスを作り、毒・麻痺などを実装
属性システム 火・水・雷などの属性を追加
クリティカル 乱数で攻撃力が2倍になる処理
逃げる バトル中に逃走できる機能
複数敵パーティ ボス+取り巻きの構成

ぜひ自分だけのオリジナル機能を追加してみてください!


reference_materials_banner-1.png

公式ドキュメント

おすすめ書籍

  • 『スッキリわかるJava入門』
  • 『Effective Java 第3版』

series_list_banner-1.png


© 2025 Java Quest - オブジェクト指向って何?RPGで理解する超入門
All Rights Reserved.

本記事は教育目的で作成されています。RPGの例を通じてプログラミング概念を楽しく学習できることを目指しています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?