Skip to content

Latest commit

 

History

History
196 lines (170 loc) · 15.7 KB

File metadata and controls

196 lines (170 loc) · 15.7 KB

Command Pattern Implementation in C# (Game Development)

C# .NET

📝 Описание

Этот проект демонстрирует реализацию паттерна Команда (Command) для системы Undo/Redo в консольной RPG игре.

Паттерн Command инкапсулирует запрос как объект, позволяя:

  • Отменять выполненные действия (Undo)
  • Хранить историю действий
  • Откладывать выполнение команд
  • Поддерживать очередь команд

🎯 Схема работы паттерна

┌─────────────────────────────────────────────────────────────────────────────┐
│                      ПАТТЕРН КОМАНДА (COMMAND)                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────┐       ┌──────────────────┐       ┌─────────────────────┐   │
│  │   Client    │       │      Invoker     │       │        Command      │   │
│  │  (Program)  │─────▶│   (InputHandler)  │─────▶│      (ICommand)     │   │
│  │             │       │                  │       │                     │   │
│  │ - создаёт   │       │ - хранит историю │       │     + Execute()     │   │
│  │   команды   │       │ - вызывает       │       │     + Undo()        │   │
│  │             │       │        Execute() │       │         △           │   │
│  └─────────────┘       │ - вызывает       │       │         │           │   │
│                        │        Undo()    │       └─────────┼───────────┘   │
│                        └────────┬─────────┘                 │               │
│                                 │                           │               │
│                                 │                    ┌──────┴──────┐        │
│                                 │                    │             │        │
│                                 ▼                    ▼             ▼        │
│                       ┌─────────────────────────────────────────────────┐   │
│                       │               Concrete Commands                 │   │
│                       ├──────────────────┬──────────────┬───────────────┤   │
│                       │    MoveCommand   │ AttackCommand│  HealCommand  │   │
│                       ├──────────────────┼──────────────┼───────────────┤   │
│                       │    - _player     │   - _enemy   │   - _player   │   │
│                       │    - _dx, _dy    │   - _damage  │  - _healPower │   │
│                       │  - _previousX/Y  │ - _prevHealth│ - _prevHealth │   │
│                       └────────┬─────────┴──────┬───────┴───────┬───────┘   │
│                                │                │               │           │
│                                ▼                ▼               ▼           │
│                       ┌─────────────────────────────────────────────────┐   │
│                       │                    Receivers                    │   │
│                       ├──────────────────┬──────────────────────────────┤   │
│                       │      Player      │            Enemy             │   │
│                       ├──────────────────┼──────────────────────────────┤   │
│                       │   + X, Y         │     + Health                 │   │
│                       │   + Health       │     + TakeDamage()           │   │
│                       │   + Move()       │                              │   │
│                       │   + Heal()       │                              │   │
│                       └──────────────────┴──────────────────────────────┘   │
│                                                                             │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                          ПОТОК ВЫПОЛНЕНИЯ                           │   │
│   │                                                                     │   │
│   │   1. Client создаёт Command ──▶ 2. Invoker.ExecuteCommand()         │   │
│   │                                                                     │   │
│   │   3. Command сохраняет состояние ──▶ 4. Command вызывает Receiver   │   │
│   │                                                                     │   │
│   │   5. Invoker сохраняет Command в Stack ──▶ 6. Undo() вызывает       │   │
│   │                                        Pop() и восстанавливает      │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

📁 Структура проекта

Command/ # Корневая папка проекта
│
├── Commands/ # Реализации команд
│ ├── ICommand.cs # Интерфейс команды
│ ├── MoveCommand.cs # Команда перемещения
│ ├── AttackCommand.cs # Команда атаки
│ └── HealCommand.cs # Команда лечения (бонус)
│
├── Helpers/ # Вспомогательные классы
│ └── DirectionHelper.cs # Определение направлений движения
│
├── Player.cs # Игрок (получатель команд)
├── Enemy.cs # Враг (получатель команд)
├── InputHandler.cs # Отправитель команд + история (Invoker)
├── Program.cs # Клиентский код
│
└── README.md # Документация

🎮 Игровая механика

Команда Действие Отмена
MoveCommand Перемещение игрока по карте (8 направлений) Возврат на предыдущую позицию
AttackCommand Нанесение урона врагу Восстановление здоровья врага
HealCommand Лечение игрока Возврат к предыдущему здоровью

Поддерживаемые направления движения:

  • Основные: север, юг, запад, восток
  • Диагональные: северо-восток, северо-запад, юго-восток, юго-запад

💻 Пример использования

// Создание игровых объектов
Player player = new Player(5, 5, 50);
Enemy goblin = new Enemy(100);
InputHandler input = new InputHandler();

// Выполнение команд
input.ExecuteCommand(new MoveCommand(player, 1, 0));   // движение на восток
input.ExecuteCommand(new AttackCommand(goblin, 15));  // атака врага
input.ExecuteCommand(new HealCommand(player, 25));    // лечение игрока

// Отмена действий (LIFO)
input.UndoLastCommand();  // отмена лечения
input.UndoLastCommand();  // отмена атаки
input.UndoLastCommand();  // отмена движения

🔧 Особенности реализации

  • ✅ Защита от null — команды проверяют получателей на null
  • ✅ Валидация данных — отрицательный урон/лечение преобразуется в 0
  • ✅ Защита от повторной отмены — проверка состояния перед отменой
  • ✅ Сохранение состояния — каждая команда хранит предыдущее состояние
  • ✅ Обработка граничных случаев — здоровье не уходит ниже 1
  • ✅ Поддержка 8 направлений — полная свобода перемещения

📊 Диаграмма классов

┌─────────────────────────────────────────────────────────────────────────────┐
│                                                                             │
│  ┌────────────────────┐                                                     │
│  │    «interface»     │                                                     │
│  │     ICommand       │                                                     │
│  ├────────────────────┤                                                     │
│  │ + Execute()        │                                                     │
│  │ + Undo()           │                                                     │
│  └────────┬───────────┘                                                     │
│           │                                                                 │
│           △                                                                │
│      ┌────┴────┬───────────────────┐                                        │
│      │         │                   │                                        │
│  ┌───┴────┐ ┌───┴────┐         ┌───┴────┐                                   │
│  │ Move   │ │Attack  │         │ Heal   │                                   │
│  │Command │ │Command │         │Command │                                   │
│  └───┬────┘ └───┬────┘         └───┬────┘                                   │
│      │         │                   │                                        │
│      ▼         ▼                   ▼                                        │
│  ┌───────┐ ┌───────┐           ┌───────┐                                    │
│  │Player │ │Enemy  │           │Player │                                    │
│  └───────┘ └───────┘           └───────┘                                    │
│      │                            △                                        │
│      │ (только для MoveCommand)   │                                         │
│      ▼            ▼               │                                         │ 
│  ┌────────────────────────────┐   │                                         │
│  │     DirectionHelper        │   │                                         │
│  │        (static)            │ ──┘                                         │
│  │ + GetDirectionName()       │                                             │
│  └────────────────────────────┘                                             │
│                                                                             │
│  ┌────────────────────┐                                                     │
│  │   InputHandler     │                                                     │
│  ├────────────────────┤                                                     │
│  │ - _commandHistory  │                                                     │
│  │   (Stack)          │                                                     │
│  ├────────────────────┤                                                     │
│  │ + ExecuteCommand() │                                                     │
│  │ + UndoLastCommand()│                                                     │
│  └────────────────────┘                                                     │
└─────────────────────────────────────────────────────────────────────────────┘

📚 Что демонстрирует этот пример

  1. Инкапсуляцию запроса как объекта — каждая команда самостоятельна
  2. Отделение отправителя от получателя — InputHandler не знает о Player и Enemy
  3. Возможность отмены операций — полная поддержка Undo
  4. Расширяемость — добавление новых команд не требует изменения существующего кода

👨‍💻 Автор

Vladimir Vaize | GitHub | Telegram Channel


⭐ Если этот проект был полезен, поставьте звезду на GitHub!