ゲームキャラクター開発
CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 90/91。
チャレンジ
簡単Game Character Developmentシステムを構築しましょう。このシステムでは、異なるキャラクタークラスが固有の能力を使って戦います。継承、インターフェース、トレイト、カプセル化がゲームのコンテキストでどのように連携するかを示すため、経験値とレベルアップの仕組みを備えたキャラクター階層を作成します。
コードを6つのファイルに整理します。
Ability.php:2つのメソッド、getName(): stringとuse(Character $target): stringを持つAbilityインターフェースをDefineします。この契約により、固有の効果に関係なく、すべての能力を一貫して使用できます。CombatLogger.php:logAction(string $action): stringメソッドを提供するCombatLoggerトレイトをCreateします。このメソッドは、アクション文字列の先頭に"[COMBAT] "を付けて返します。キャラクターはこのトレイトを使用して、戦闘メッセージを一貫した形式にします。Character.php:Ability ファイルと CombatLogger ファイルを読み込みます。CombatLoggerトレイトを使用する抽象CharacterクラスをCreateします。name(string、public readonly)にはコンストラクター・プロモーションを使用します。health(int、100から開始)、level(int、1から開始)、experience(int、0から開始)には private プロパティを含めます。以下を実装します。getHealth(): intとgetLevel(): int:private プロパティのゲッターtakeDamage(int $amount): void:healthを減少させますが、0未満にはしないheal(int $amount): void:healthを増加させますが、100を超えないgainExperience(int $xp): string:XPを追加します。experienceが100以上になった場合はレベルアップし(XPを0にリセットし、levelを増加させ、HPを20回復する)、"[name] leveled up to [level]!"を返します。それ以外の場合は"[name] gained [xp] XP"を返します。isAlive(): bool:healthが0より大きい場合にtrueを返しますabstract getSpecialAbility(): Ability:各キャラクタータイプが固有の能力を提供しますattack(Character $target): string:targetに10ダメージを与え、logAction()を使用して"[COMBAT] [name] attacks [target name] for 10 damage"を返します
Warrior.php:Characterファイルを読み込みます。CharacterをextendingするWarriorクラスをCreateします。Abilityを実装するanonymous classを返すようにgetSpecialAbility()を実装します。getName()は"Shield Bash"を返しますuse()は25ダメージを与え、"[COMBAT] Shield Bash hits [target name] for 25 damage!"を返します(トレイトのlogAction()を使用します)
Mage.php:Characterファイルを読み込みます。CharacterをextendingするMageクラスをCreateします。Abilityを実装するanonymous classを返すようにgetSpecialAbility()を実装します。getName()は"Fireball"を返しますuse()は35ダメージを与え、"[COMBAT] Fireball engulfs [target name] for 35 damage!"を返します
main.php:WarriorファイルとMageファイルを読み込みます。2つの入力、つまりキャラクターデータ(JSON)と一連の戦闘アクション(JSON)を受け取ります。Characters JSONの形式:
[{"type": "warrior", "name": "Thorin"}, {"type": "mage", "name": "Gandalf"}]Actions JSONの形式:
[{"action": "attack", "attacker": 0, "target": 1}, {"action": "special", "attacker": 1, "target": 0}, {"action": "xp", "character": 0, "amount": 100}, {"action": "status", "character": 0}]すべてのキャラクターをCreateし、array(インデックス0、1など)に格納します。各アクションを処理します。
"attack":attackerインデックスのCharacterがtargetを攻撃し、結果を出力します"special":Characterがtargetにspecial abilityを使用し、結果を出力します"xp":Characterがexperienceをgainし、結果を出力します"heal":Characterが指定されたamountだけ回復し、"[name] healed to [health] HP"を出力します"status":"[name] - Level [level], HP: [health], Alive: [Yes/No]"を出力します
各結果を新しい行に出力します。
このシステムは、abstract classが共有されるCharacterの動作をどのようにDefineするか、interfaceがAbilityが一貫した契約に従うことをどのように保証するか、traitが再利用可能なロギング機能をどのように提供するか、そしてanonymous classが単一用途のクラスでコードベースを煩雑にすることなく固有のAbility実装をどのように作成するかを示しています。
自分で試してみよう
<?php
require_once 'Warrior.php';
require_once 'Mage.php';
// 入力を読み取る
$charactersJson = trim(fgets(STDIN));
$actionsJson = trim(fgets(STDIN));
// JSON入力を解析する
$charactersData = (array)json_decode($charactersJson, true);
$actionsData = (array)json_decode($actionsJson, true);
// TODO: キャラクターオブジェクトを格納する配列を作成する
$characters = [];
// TODO: $charactersDataをループしてWarriorまたはMageオブジェクトを作成する
// "type"フィールドに基づいて、$characters配列に格納する
// TODO: $actionsData内の各アクションを処理する
// これらのアクションタイプを処理する:
// - "attack": 攻撃者インデックスのキャラクターがターゲットを攻撃する; 結果を出力する
// - "special": キャラクターがgetSpecialAbility()->use()をターゲットに使用する; 結果を出力する
// - "xp": キャラクターが経験値を獲得する; 結果を出力する
// - "heal": キャラクターが回復する; "[name] healed to [health] HP"を出力する
// - "status": "[name] - Level [level], HP: [health], Alive: [Yes/No]"を出力する
?>オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: PHPオンラインコンパイラ