Hero background image
Используйте шаблон команды для гибких и расширяемых игровых систем
Эта страница была переведена с использованием машинного перевода. Для просмотра исходной версии, которая является точной и служит источником достоверной информации,

Внедрение распространенных шаблонов программирования игр в проект Unity поможет вам эффективно создавать и поддерживать чистую, упорядоченную и читаемую кодовую базу. Образцы дизайна сокращают время рефакторинга и тестирования, ускоряя процессы разработки и создавая прочную основу для развития вашей игры, команды и бизнеса.

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

На этой странице объясняется схема дизайна команд.

Контент основан на бесплатной электронной книге «Обновите код с помощью шаблонов игрового программирования».

Подробнее об этом см. в сериях шаблонов дизайна игрового программирования Unity на странице Лучшие методики Unity Hub или по этим ссылкам:

Понимание шаблона команды

Схема программирования команд — одна из исходных для «банды четырех», она полезна для отслеживания определенного ряда действий. Скорее всего, вы видели шаблон команды, если играли в игру, в которой используются функции отмены или отмены ввода, или вели историю ввода в списке. Представьте себе стратегию, где пользователь может спланировать несколько ходов перед их реальным выполнением. Это командная схема.

Шаблон команды позволяет представлять действия в виде объектов. Инкапсуляция действий как объектов позволяет создать гибкую и расширяемую систему управления поведением GameObject в ответ на ввод данных пользователем. Это работает путем инкапсуляции одного или нескольких вызовов метода в «командный объект», а не прямого вызова метода. Эти командные объекты можно хранить в коллекции, например, в очереди или стеке, которая работает как небольшой буфер.

Хранение командных объектов таким образом позволяет контролировать время их выполнения, потенциально откладывая ряд действий для последующего воспроизведения. Аналогичным образом, вы можете отменять или отменять их, а также гибко управлять выполнением каждого командного объекта.

Вот несколько распространенных вариантов применения шаблона в разных игровых жанрах:

  • В стратегии реального времени шаблон команды можно использовать для постановки юнита и действий по строительству в очередь. Затем игра выполняет каждую команду по мере поступления ресурсов.
  • В пошаговой стратегической игре игрок мог выбрать единицу измерения, а затем хранить ее ходы или действия в очереди или другой коллекции. В конце хода игра должна была выполнить все команды в очереди игрока.
  • В головоломке шаблон команды позволяет игроку отменять и отменять действия.
  • В файтинге чтение нажатий на кнопки или движений геймпада в определенном списке команд может приводить к появлению выпадающих списков и особых движений.
Шаблон команды в примере проекта
Шаблон команды в примере проекта

Ознакомьтесь с примером проекта на GitHub, демонстрирующим различные шаблоны программирования в контексте игровой разработки, включая шаблон команды.

В этом примере игрок может перемещаться по лабиринту, нажимая кнопки с левой стороны. Во время движения игрока вы увидите тропу движений. Но что еще важнее, вы можете отменить и отменить предыдущие действия.

Чтобы найти соответствующую сцену в проекте, перейдите в папку «9 Command».

Командный объект и вызов команды

Чтобы реализовать шаблон команды, вам потребуется общий объект, содержащий ваши действия. Этот командный объект будет содержать логику и способ ее отмены.

Есть несколько способов реализации, но вот простая версия с интерфейсом ICommand:

общедоступный интерфейс ICommand
{
void Execute();
void Undo();
}

В этом случае интерфейс ICommand будет применен к каждому игровому действию (это также можно реализовать с помощью абстрактного класса).

Каждый командный объект будет отвечать за собственные методы выполнения и отмены. Добавление новых команд в игру не повлияет на существующие.

Класс CommandInvoker отвечает за выполнение и отмену команд. В дополнение к методам ExecuteCommand и UndoCommand, он имеет стек отмены для хранения последовательности командных объектов.

Пример: Невозможное движение

В примере проекта вы можете перемещать игрока по небольшому лабиринту. Простой вариант изменения положения игрока — создать PlayerMover.

Для этого вам нужно пройти через вектор3 в метод Move, чтобы направить игрока по четырем направлениям компаса. Кроме того, вы можете использовать Raycast для обнаружения стен в соответствующем слое LayerMask. Конечно, реализация того, что нужно применить к шаблону команды, осуществляется отдельно от самого шаблона.

MoveCommand
THE COMMANDINVOKER, ICOMMAND И MOVECOMMAND
MoveCommand

Чтобы выполнить эту схему, введите метод перемещения PlayerMover в качестве объекта. Вместо вызова Move напрямую создайте новый класс MoveCommand, который реализует интерфейс ICommand.

общедоступный класс MoveCommand : ICommand
{
PlayerMover playerMover;
перемещение Vector3;
общедоступный MoveCommand(плеер PlayerMover, Vector3 moveVector)
{
this.playerMover = игрок;
this.movement = moveVector;
}
public void Execute()
{
playerMover.Move(перемещение);
}
Public void Undo()
{
playerMover.Move(-movement);
}
}

Логика, которую вы хотите реализовать, входит сюда, поэтому вызовите Move with the Movement vector.

ICommand также использует метод Undo, чтобы вернуть сцену в предыдущее состояние. В этом случае логика Undo вычитает вектор движения, толкая игрока в противоположную сторону.

MoveCommand сохраняет все необходимые параметры. Настройте их с помощью конструктора. В этом случае вы сохраните соответствующий компонент PlayerMover и вектор движения.

Создав командный объект и сохранив необходимые параметры, используйте статические методы ExcutCommand и UndoCommand CommandInvoker, чтобы использовать их в MoveCommand. Это выполняет выполнение или отмену MoveCommand и отслеживает командный объект в стеке отмены.

InputManager не вызывает метод перемещения PlayerMover напрямую. Вместо этого добавьте дополнительный метод RunMoveCommand, чтобы создать новую команду MoveCommand и отправить ее CommandInvoker.

Затем настройте различные события OnClick кнопок интерфейса, чтобы вызвать RunPlayerCommand четырьмя векторами движения.

Ознакомьтесь с примером проекта, чтобы узнать подробности о реализации InputManager. Вы также можете настроить собственный ввод с помощью клавиатуры или геймпада. Теперь ваш игрок может перемещаться по лабиринту. Нажмите кнопку «Отменить», чтобы перейти к начальному квадрату.

Плюсы и минусы

Реализация воспроизводимости или невозможности проста, как и генерация коллекции командных объектов. Вы также можете использовать буфер команд для последовательного воспроизведения действий с определенными элементами управления.

Например, взгляните на файтинг, где несколько нажатий на определенные кнопки вызывают комбинированный ход или атаку. Хранение действий игрока с шаблоном команды значительно упрощает настройку этих выпадающих списков.

С другой стороны, схема команд вносит больше структуры, как и другие шаблоны дизайна. Вам нужно решить, в каких аспектах дополнительные классы и интерфейсы дают достаточные преимущества для развертывания командных объектов в приложении.

Изучив основы, вы можете влиять на тайминг команд и воспроизводить их последовательно или наоборот в зависимости от контекста.

При включении шаблона команды учитывайте следующее:

  • Создать больше команд: Пример проекта содержит только один тип командного объекта — MoveCommand. Вы можете создать любое количество командных объектов, которые реализуют ICommand, и отслеживать их с помощью CommandInvoker.
  • Добавление функции переделки требует добавления другого стека: Отменив командный объект, перенесите его в отдельный стек, отслеживающий операции переделки. Это позволяет быстро просмотреть историю отмены или перепроверить эти действия. Очистите стек переделки, когда пользователь вызывает совершенно новое движение (реализацию можно найти в примере проекта).
  • Используйте другую коллекцию для объектов команды буфера: Очередь может быть удобнее, если нужно поведение first in, first out (FIFO). Если вы используете список, отслеживайте текущий активный индекс; команды перед активным индексом невыполнимы. Команды после индекса переделываются.
  • Ограничьте размер стеков: Операции отмены и отмены могут быстро выйти из-под контроля. Ограничьте стеки минимальным количеством команд.
  • Передавайте все необходимые параметры в конструктор: Это помогает интегрировать логику, как показано в примере MoveCommand.
  • CommandInvoker, как и другие внешние объекты, не видит внутренней работы командного объекта, а только вызывает Execute или Undo. Предоставьте командному объекту все данные, необходимые для работы при вызове конструктора.
синяя электронная книга
Дополнительные ресурсы

Дополнительные советы по использованию шаблонов дизайна в приложениях Unity, а также принципов SOLID можно найти в бесплатной электронной книге «Обновите код с помощью шаблонов программирования игр».

Вы найдете все современные технические электронные книги Unity и статьи в центре лучших методик. Электронные книги также доступны на странице «Передовые методы» в документации.

Понравился ли вам этот контент?