Фундаментальная концепция для создания увлекательных и захватывающих впечатлений

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

Один из способов сделать это — использовать шаблоны проектирования.

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

В своей предыдущей статье я уже говорил о том, как фреймворк GameplayKit от Apple позволил разработчикам получить отправную точку для достижения упомянутых выше целей шаблонов проектирования. Наряду с архитектурой ECS шаблон состояния приходит на помощь в нескольких ситуациях во время разработки игр. Например, это значительно улучшило и ускорило мой процесс разработки. Это позволило создать всего за три дня Сила Воли — Битва Магелло и даже разработать Саймон-говорит аркадную игру» всего за 16 часов от концепции до Testflight!

Так что же такое шаблон состояния?

Паттерн состояния — это поведенческий шаблон проектирования, который позволяет объекту изменять свое поведение на основе своего внутреннего состояния, чтобы динамично и гибко реагировать на различные входные данные и события.

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

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

Возможно, вы уже применяете его концепции, не задумываясь об этом; Очень наивным подходом может быть использование перечислителя в качестве активного состояния и ветвление нашего кода по мере необходимости, и в зависимости от вашей цели это может работать. Иногда «если» — это все, что вам нужно.

Объектно-ориентированное решение

Но если вам нужно что-то, что может включать больше состояний, и ваша цель состоит в том, чтобы иметь что-то, с чем вы сможете работать в долгосрочной перспективе, объектно-ориентированный подход, следующий принципам SOLID, в какой-то момент облегчит вашу жизнь. Для этого мы можем реализовать конечный автомат (FSM), математическую модель вычислений, которая описывает поведение системы как последовательность состояний и переходов между этими состояниями.

Чтобы определить некоторые ключевые моменты, FSM:

  1. Имеет конечное число состояний
  2. Может находиться только в одном состоянии одновременно
  3. Каждое государство несет ответственность за одно дело
  4. Активное состояние получает ввод и отвечает

Давайте попробуем сделать один

Вот черновик FSM, который я сейчас настраиваю для игры, которая скоро будет опубликована, поэтому фрагменты кода будут на C#, поскольку я разрабатываю его на Unity.

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

Поскольку я уже был знаком с GameplayKit, я сразу же подумал о разработке конечного автомата для обработки состояний игрового цикла в соответствии с требованиями, которые мы написали в нашем документе по дизайну игры. (Если вы не пишете его, я советую вам проверить эту статью о 5 причинах, почему вы должны это сделать).

Цикл нашей игры можно разбить на следующие состояния:

  • ScrollingState
  • BattleState
  • PauseState
  • GameOverState

Боевое состояние также может быть представлено другим конечным автоматом с BeginBattleState, HeroTurnState, EnemyTurnState и EndBattleState.

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

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

Это отправная точка для простого состояния, следующего за тем, которое использовалось в GameplayKit, со ссылкой на конечный автомат, в котором оно находится, виртуальными методами для обработки поведения при переходах (и какие из них допустимы) и циклами обновления.

Затем StateMachine можно реализовать следующим образом:

Конечный автомат содержит текущее состояние, предыдущее состояние и список переданных ему состояний. Когда он готов к запуску, он входит в первый элемент списка, если он доступен, и вызывает метод Start состояния; Затем метод Update распространяется на метод State. Чтобы войти в следующее состояние, машина состояний проверяет, есть ли в списке состояние этого типа и является ли это допустимым переходом; если он действителен, то вызовите метод Exit предыдущего состояния и метод Start нового.

Теперь мы можем приступить к реализации наших конкретных классов. Давайте просто рассмотрим GameStateMachine, ScrollingState и BattleState, чтобы кратко продемонстрировать временной переход между ними двумя.

Просто грубый набросок, чтобы заставить его работать: когда GameManager создает экземпляр GameStateMachine и вызывает метод запуска, он запускает цикл, в котором ScrollingGameState и BattleGameState будут переключаться, когда таймер достигает своего времени, изменяя текст и компонент изображения в соответствии с ними. Вот результат для справки:

Подведение итогов

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

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

Кроме того, принцип инверсии зависимостей (DIP) не соблюдается, поскольку он тесно связан с игровыми объектами внутри сцены, хотя и только для демонстрации. Важно помнить, что шаблон State — это лишь один из многих шаблонов проектирования, которые можно использовать для решения проблем при разработке игр. Могут быть другие шаблоны или даже более новые решения, которые могут сделать ваш код чище и эффективнее.

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