ゲームキャラクター開発
CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 86/87。
このチャレンジでは、複雑でインタラクティブなエンティティのモデル化におけるOOPの力を示す、ゲームキャラクター開発システムを構築します。
Character クラスの base が、health、name、level などの共通属性を定義するキャラクター階層を設計します。Warrior、Mage、Archer などの特殊化されたクラスは、固有の abilities と combat スタイルでこの base を拡張します。
ここではインターフェースが自然に機能します。Attackable は戦闘メソッドを定義し、Healable は回復能力を扱うことができます。Mage は両方を実装する一方で、Warrior は攻撃だけに集中するかもしれません。
異なる攻撃動作に Strategy パターンを使用することを検討し、キャラクターが戦闘スタイルを動的に切り替えられるようにします。State パターンを使えば、動作に影響を与える通常、毒状態、スタン状態などのキャラクターの状態を管理できます。
character が武器や防具を継承するのではなく、それらを「持つ」装備システムについて考えてみましょう。character class や damage の種類には enum を使用し、カプセル化を適用して、無効な変更からステータスを保護します。
チャレンジ
簡単OOPによる複雑でインタラクティブなゲームエンティティのモデル化の力を示す、ゲーム Character Development システムを構築しましょう!異なる combat スタイル、特殊な abilities、そして Character の振る舞いに影響する state システムを備えた Character hierarchy を作成します。
コードを7つのファイルに整理します。
DamageType.java: ゲーム内のさまざまな damage の種類を表す enum を作成します。PHYSICAL、MAGICAL、RANGEDの値を含めます。private フィールドdescription(String)、それを設定する constructor、および getter を追加します。Physical damage の description は "brute force"、magical は "arcane energy"、ranged は "precision strike" にします。Attackable.java: combat capabilities を定義する interface を作成します。攻撃を説明する String を返すattack(Character target)メソッドと、DamageType を返すgetDamageType()メソッドを宣言します。Healable.java: 回復 abilities のための interface を作成します。回復アクションを説明する String を返すheal(int amount)メソッドを宣言します。Character.java: すべてのゲーム Character の abstract な base class を作成します。name(String)、health(int)、maxHealth(int)、level(int)の private フィールドを含めます。constructor は name、maxHealth、level を受け取り、最初に health を maxHealth と等しく設定します。すべてのフィールドの getter を含めます。health が 0 以上 maxHealth 以下に保たれるようにする protected メソッドsetHealth(int health)を追加します。health を減少させ、"[name] takes [damage] damage! Health: [health]/[maxHealth]"を返すtakeDamage(int damage)メソッドを作成します。health が 0 より大きい場合に true を返すisAlive()メソッドを追加します。String を返す abstract メソッドgetCharacterClass()を宣言します。Warrior.java: Character を拡張し、Attackable を実装する class を作成します。strength(int)の private フィールドを追加します。constructor は name、maxHealth、level、strength を受け取ります。getCharacterClass()は"Warrior"を返すように実装します。getDamageType()はPHYSICALを返すように実装します。attack(Character target)は strength と level の合計に等しい damage を与え、target の takeDamage メソッドを呼び出し、"[name] strikes with [damageType description] for [damage] damage!"に改行と takeDamage の結果を続けたものを返すように実装します。Mage.java: Character を拡張し、Attackable と Healable の両方を実装する class を作成します。intelligence(int)とmana(int)の private フィールドを追加します。constructor は name、maxHealth、level、intelligence、mana を受け取ります。getCharacterClass()は"Mage"を返すように実装します。getDamageType()はMAGICALを返すように実装します。attack(Character target)は intelligence の 2 倍に等しい damage を与え、Warrior と同じ形式にします。heal(int amount)は setHealth を使用して health を回復し、"[name] channels healing magic! Health: [health]/[maxHealth]"を返すように実装します。Main.java: ゲームシステムを動かしましょう!カンマ区切りの command 文字列を受け取ります。CREATE_WARRIOR:name:maxHealth:level:strengthCREATE_MAGE:name:maxHealth:level:intelligence:manaATTACK:attackerName:targetNameHEAL:mageName:amountSTATUS:characterName
Character の collection を管理します。各 command を処理し、次の内容を出力します。
- CREATE_WARRIOR/CREATE_MAGE:
[name] the [characterClass] joins the battle! - ATTACK: 攻撃結果(attack メソッドが返す String)を出力します
- HEAL: heal の結果を出力します。Character が Mage でない場合は
[name] cannot healを出力します - STATUS:
[name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]
すべての command の後に
--- Battle Summary ---を出力し、その後に各 Character の status を出力します。
入力として1つのカンマ区切りの command 文字列を受け取ります。
たとえば、入力が CREATE_WARRIOR:Thorin:100:5:15,CREATE_MAGE:Gandalf:80:7:12:50,ATTACK:Thorin:Gandalf,HEAL:Gandalf:25,STATUS:Gandalf の場合、出力は次のようになります。
Thorin the Warrior joins the battle!
Gandalf the Mage joins the battle!
Thorin strikes with brute force for 20 damage!
Gandalf takes 20 damage! Health: 60/80
Gandalf channels healing magic! Health: 80/80
Gandalf (Mage) - Level 7 - Health: 80/80 - Alive
--- Battle Summary ---
Thorin (Warrior) - Level 5 - Health: 100/100 - Alive
Gandalf (Mage) - Level 7 - Health: 80/80 - Aliveこの challenge では、継承(Character hierarchy)、複数の interface 実装(Mage は Attackable と Healable の両方を実装)、メソッドを持つ enum(DamageType)、polymorphism(異なる Character の種類を統一的に扱うこと)、encapsulation(protected による health 管理)を、魅力的なゲームシステムに組み合わせています!
自分で試してみよう
import java.util.Scanner;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedHashMap;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: キャラクターを管理するためにコレクションを使用する(LinkedHashMapは挿入順を保持する)
// LinkedHashMap<String, Character> characters = new LinkedHashMap<>();
// TODO: 入力をカンマで分割して個々のコマンドを取得する
// String[] commands = input.split(",");
// TODO: 各コマンドを処理する:
// - CREATE_WARRIOR:name:maxHealth:level:strength
// Print: "[name] the Warrior joins the battle!"
//
// - CREATE_MAGE:name:maxHealth:level:intelligence:mana
// Print: "[name] the Mage joins the battle!"
//
// - ATTACK:attackerName:targetName
// attackメソッドからの攻撃結果を出力する
//
// - HEAL:mageName:amount
// 回復結果を出力する。Mageでない場合は "[name] cannot heal"
//
// - STATUS:characterName
// 出力: "[name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]"
// TODO: After all commands, print "--- Battle Summary ---"
// 次に各キャラクターのステータスを出力する
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造自分で練習してみよう: Javaオンラインコンパイラ