Menu
Coddy logo textTech

ゲームキャラクターコンポーネント

CoddyのC#ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 69/70。

challenge icon

チャレンジ

簡単

コンポーネントベースのアーキテクチャパターンを使用して、ゲームのキャラクターシステムを構築しましょう!硬直した継承階層を作成する代わりに、特定の動作を処理する独立したコンポーネントをアタッチすることでキャラクターを構成します。これはゲーム開発で広く使用されている柔軟なアプローチです。

コードは5つのファイルに分けて構成します:

  • IComponent.cs: Game.Components名前空間にIComponentインターフェースを定義します。すべてのコンポーネントは、そのコンポーネントが何をしているかを出力するUpdate()メソッドを持つ必要があります。
  • HealthComponent.cs: IComponentを実装するHealthComponentクラスを作成します。現在と最大の体力を追跡し、TakeDamage(int amount)Heal(int amount)メソッドを持つ必要があります。体力は0未満や最大値を超えてはいけません。体力が変化するたびに新しい体力値を渡して発生するevent Action<int> HealthChangedを含めてください。Update()メソッドは現在の体力のステータスを出力する必要があります。
  • InventoryComponent.cs: IComponentを実装するInventoryComponentクラスを作成します。アイテム名のリストを管理し、AddItem(string item)およびRemoveItem(string item)(成功したかどうかを示すboolを返す)メソッドを持ちます。Update()メソッドはインベントリの内容を出力する必要があります。
  • Character.cs: コンポーネントのコレクションを保持するCharacterクラスをGame名前空間に作成します。キャラクターにはNameプロパティと以下のメソッドが必要です:
    • AddComponent(IComponent component) - キャラクターにコンポーネントをアタッチします
    • GetComponent<T>() where T : IComponent - 型Tの最初のコンポーネントを返します。見つからない場合はnullを返します
    • UpdateAll() - アタッチされている各コンポーネントのUpdate()を呼び出します
  • Program.cs: キャラクターを作成し、コンポーネントをアタッチし、コマンドを処理することで、すべてをまとめます。

以下の入力を受け取ります:

  • キャラクター名
  • HealthComponentの初期最大体力
  • 処理するコマンドの数
  • 各コマンド:アクションとそれに関連するデータ

コマンドの形式:

damage
{amount}

heal
{amount}

add_item
{itemName}

remove_item
{itemName}

update

出力形式:

  • 体力が変化したとき(イベント経由):Health changed: {newHealth}
  • アイテムを追加したとき:Added: {itemName}
  • アイテムを削除したとき:Removed: {itemName} または Item not found: {itemName}
  • HealthComponentのUpdate()Health: {current}/{max}
  • InventoryComponentのUpdate()Inventory: {item1}, {item2}, ... または Inventory: empty

例えば、入力が以下の場合:

Hero
100
7
add_item
Sword
add_item
Shield
damage
30
heal
10
remove_item
Potion
remove_item
Sword
update

出力は以下のようになります:

Added: Sword
Added: Shield
Health changed: 70
Health changed: 80
Item not found: Potion
Removed: Sword
Health: 80/100
Inventory: Shield

キャラクターが特別なものから継承していないことに注目してください。単に振る舞いを提供するコンポーネントを保持しているだけです。GetComponent<T>()メソッドは型安全な取得のためにジェネリクスを使用し、イベントは体力が変化したときに通知します。このコンポジション(合成)アプローチにより、コンポーネントを自由に組み合わせて使うことができます!

自分で試してみよう

using System;
using Game;
using Game.Components;

class Program
{
    public static void Main(string[] args)
    {
        // キャラクター名を読み込む
        string characterName = Console.ReadLine();
        
        // 初期の最大体力を読み込む
        int maxHealth = Convert.ToInt32(Console.ReadLine());
        
        // コマンドの数を読み込む
        int numCommands = Convert.ToInt32(Console.ReadLine());
        
        // TODO: 指定された名前で Character を作成する
        
        // TODO: maxHealth を持つ HealthComponent と InventoryComponent を作成する
        
        // TODO: HealthChanged イベントを購読し、「Health changed: {newHealth}」と出力するようにする
        
        // TODO: 両方のコンポーネントをキャラクターに追加する
        
        // TODO: 各コマンドを処理する
        for (int i = 0; i < numCommands; i++)
        {
            string command = Console.ReadLine();
            
            // TODO: 各コマンドタイプを処理する:
            // - "damage": 値を読み込み、health component の TakeDamage を呼び出す
            // - "heal": 値を読み込み、health component の Heal を呼び出す
            // - "add_item": アイテム名を読み込み、inventory component の AddItem を呼び出す
            // - "remove_item": アイテム名を読み込み、inventory component の RemoveItem を呼び出す
            // - "update": キャラクターの UpdateAll を呼び出す
        }
    }
}

オブジェクト指向プログラミングのすべてのレッスン