Menu
Coddy logo textTech

ゲームキャラクター開発

CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 90/91。

challenge icon

チャレンジ

簡単

Game Character Developmentシステムを構築しましょう。このシステムでは、異なるキャラクタークラスが固有の能力を使って戦います。継承、インターフェース、トレイト、カプセル化がゲームのコンテキストでどのように連携するかを示すため、経験値とレベルアップの仕組みを備えたキャラクター階層を作成します。

コードを6つのファイルに整理します。

  • Ability.php:2つのメソッド、getName(): stringuse(Character $target): string を持つ Ability インターフェースをDefineします。この契約により、固有の効果に関係なく、すべての能力を一貫して使用できます。
  • CombatLogger.phplogAction(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(): intgetLevel(): 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オンラインコンパイラ