Структура игрового блока RTS

18

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

Как я вижу, есть два способа сделать это.

  1. Единый универсальный класс Unit с флагами, который определяет, что он может / не может делать (затем создает экземпляры в статическом массиве и захватывает их при необходимости)
  2. Абстрактный класс юнитов с абстрактными методами для специфических для Юнита действий, таких как (Атака, Урожай, Патруль), которые затем должны быть реализованы в подклассах , даже если юнит не может ничего собрать.

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

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

Это даже правильный подход к этой проблеме?
В такой игре, как AoE, у каждого юнита есть, как я полагаю, какой-то Список действий / Приказов, мне бы очень хотелось узнать, как добиться чего-то похожего на то, где я могу просто кодировать каждое Действие / Орден один раз, и затем дайте это всем подразделениям, которые нуждаются в указанном действии.

Если мне неясно (весьма правдоподобно) или вам нужна дополнительная информация о том, что именно я ищу, просто спросите меня в комментарии.

Даниэль Холст
источник

Ответы:

25

Общий подход состоит в том, чтобы иметь компонентный подход, в котором базовый класс "Unit" просто реализует самые основные аспекты, которые имеют все модули, в то время как каждый модуль имеет список из нескольких объектов-компонентов, которые говорят, что он может делать, и как оно это делает

Например, танк может иметь компоненты Mobile, Destructible, Attacker, неподвижная турель только Destructible, Attackerи комбайн Mobile, Destructible, Harvester. Эти классы будут включать весь код, необходимый для реализации этих поведений. Взаимодействие между компонентами ( Attackerможет только повредить то, что есть Destructible) может быть реализовано с помощью проверки компонента на наличие необходимого компонента в другом модуле, а затем непосредственного взаимодействия с этим компонентом.

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

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

Philipp
источник
Так в единстве я тогда отключил бы и включил компоненты как необходимый?
Даниэль Холст
@DanielHolst Нет, вы бы добавили и удалили их по мере необходимости. Вы можете сделать это в редакторе Unity или с помощью scrips, используя gameObject.AddComponentи gameObject.RemoveComponent.
Филипп
ну, ладно, но скажи для действия / приказа "переместить". как бы подразделение узнало, когда заказ был выполнен? и как бы я поставил в очередь заказы?
Даниэль Холст
2
@DanielHolst Я думаю, вы что-то не так поняли. В Movingозначает компонент «этот блок , как правило , способен к движению». Компонент постоянно прикреплен к нему, независимо от того, перемещается устройство или нет. Это не значит, что оно движется прямо сейчас . Хотя вы могли бы также сделать это таким образом, добавляя MoveOrderкомпонент к нему и с самим этим компонентом удалить из блока , когда заказ выполнен или отменен.
Филипп
1
@DanielHolst Теперь вы дрейфуете в направлении отряда ИИ, который представляет собой еще одну банку червей. Возможный подход заключается в том, чтобы иметь библиотеку компонентов AIScript, которые либо предполагают наличие определенных компонентов, либо изменяют свое поведение в зависимости от того, какие компоненты имеет модуль. Но на самом деле это слишком сложная тема для комментариев.
Филипп
4

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

Росс Тейлор-Тернер
источник
это будет чрезвычайно сложно реализовать?
Даниэль Холст
Подобные шаблоны используются для облегчения реализации в целом. Если вы не можете решить, какой подход выбрать, будет хорошей идеей начать с как можно более простого и расширить свой выбор, увеличивая функциональность. Как только вы почувствуете проблему, вы можете либо изменить рефакторинг, либо переписать подход, который лучше соответствует вашей ситуации.
Росс Тейлор-Тернер
1
@DanielHolst Я заметил, что у вашего вопроса есть Unityфлаг. В Unity уже есть встроенная система компонентов, и она сильно предпочитает композицию наследованию . Одним простым методом было бы создать a MonoBehaviourдля каждого из ваших типов действий, а затем прикрепить к каждому типу юнита заранее готовые действия, которые он может выполнить (настраивая экземпляры действий с деталями для каждого типа, такими как значения ущерба и затраты). Это позволяет управлять созданием ваших данных, так что вы можете легко создавать множество пользовательских типов.
DMGregory
@DanielHolst Это зависит от вашего определения «чрезвычайно сложно». Мой ответ более подробно о том, как это можно реализовать.
Филипп