Menu
Coddy logo textTech

Компонент игрового персонажа

Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy — урок 69 из 70.

challenge icon

Задание

Легко

Давайте создадим систему игровых персонажей, используя паттерн компонентной архитектуры! Вместо создания жестких иерархий наследования, вы будете составлять персонажей, прикрепляя независимые компоненты, которые управляют определенным поведением — это гибкий подход, широко используемый в разработке игр.

Вы организуете свой код в пяти файлах:

  • IComponent.cs: Определите интерфейс IComponent в пространстве имен Game.Components. Каждый компонент должен иметь метод Update(), который выводит информацию о том, что делает компонент.
  • HealthComponent.cs: Создайте класс HealthComponent, реализующий IComponent. Он должен отслеживать текущие и максимальные очки здоровья, имея методы TakeDamage(int amount) и Heal(int amount). Здоровье никогда не должно опускаться ниже 0 или превышать максимум. Включите событие event Action<int> HealthChanged, которое срабатывает при каждом изменении здоровья, передавая новое значение здоровья. Метод Update() должен выводить текущий статус здоровья.
  • InventoryComponent.cs: Создайте класс InventoryComponent, реализующий IComponent. Он управляет списком названий предметов с помощью методов AddItem(string item) и RemoveItem(string item) (возвращает bool, указывающий на успех операции). Метод Update() должен выводить содержимое инвентаря.
  • Character.cs: Создайте класс Character в пространстве имен Game, который содержит коллекцию компонентов. Вашему персонажу требуется свойство Name и следующие методы:
    • AddComponent(IComponent component) — прикрепляет компонент к персонажу
    • GetComponent<T>() где 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}
  • Метод Update() у HealthComponent: Health: {current}/{max}
  • Метод Update() у InventoryComponent: 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: Создать HealthComponent с maxHealth и InventoryComponent
        
        // TODO: Подписаться на событие HealthChanged для вывода: Health changed: {newHealth}
        
        // TODO: Добавить оба компонента персонажу
        
        // TODO: Обработать каждую команду
        for (int i = 0; i < numCommands; i++)
        {
            string command = Console.ReadLine();
            
            // TODO: Обработать каждый тип команды:
            // - "damage": считать количество, вызвать TakeDamage у компонента здоровья
            // - "heal": считать количество, вызвать Heal у компонента здоровья
            // - "add_item": считать название предмета, вызвать AddItem у компонента инвентаря
            // - "remove_item": считать название предмета, вызвать RemoveItem у компонента инвентаря
            // - "update": вызвать UpdateAll у персонажа
        }
    }
}

Все уроки раздела Объектно-ориентированное программирование