Я только начинаю думать о компонентном дизайне. Я не знаю, каков «правильный» способ сделать это.
Вот сценарий. Игрок может оборудовать щит. Щит нарисован в виде пузыря вокруг игрока, он имеет отдельную форму столкновения и уменьшает урон, который игрок получает от эффектов области.
Как устроен такой щит в игре на основе компонентов?
Что меня смущает, так это то, что у щита, очевидно, есть три компонента, связанные с ним.
- Снижение ущерба / фильтрация
- Спрайт
- Коллайдер
Что еще хуже, различные варианты щитов могут иметь еще большее поведение, все из которых могут быть компонентами:
- увеличить максимальное здоровье игрока
- регенерация здоровья
- отклонение снаряда
- так далее
Я обдумываю это? Должен ли щит быть просто супер компонентом?
Я действительно думаю, что это неправильный ответ. Поэтому, если вы думаете, что это путь, пожалуйста, объясните.Должен ли щит быть его собственной сущностью, которая отслеживает местоположение игрока?
Это может затруднить реализацию фильтрации повреждений. Это также размывает границы между присоединенными компонентами и объектами.Должен ли щит быть компонентом, в котором размещены другие компоненты?
Я никогда не видел и не слышал ничего подобного, но, возможно, это обычное дело, и я просто еще не достаточно глубоко.Должен ли щит быть просто набором компонентов, которые добавляются в плеер?
Возможно, с дополнительным компонентом для управления другими, например, чтобы они могли быть удалены как группа. (случайно оставить компонент уменьшения урона, теперь это было бы весело).Что-то еще, что очевидно для кого-то с большим опытом компонентов?
источник
Ответы:
Изменить: я думаю, что не достаточно "автономного поведения" для отдельной сущности. В этом конкретном случае щит следует за целью, работает на цель и не переживает цель. Хотя я склонен согласиться с тем, что в концепции «объекта-щита» нет ничего плохого, в этом случае мы имеем дело с поведением, которое прекрасно вписывается в компонент. Но я также сторонник чисто логических сущностей (в отличие от полноценных систем сущностей, в которых вы можете найти компоненты Transform и Rendering).
Посмотрите на это с другой точки зрения; При добавлении компонента добавляются и другие компоненты, а после удаления дополнительные компоненты также исчезают.
Это может быть решением, оно будет способствовать повторному использованию, однако оно также более подвержено ошибкам (например, для упомянутой вами проблемы). Это не обязательно плохо. Вы можете узнать новые комбинации заклинаний методом проб и ошибок :)
Я собираюсь уточнить немного.
Я полагаю, вы заметили, как некоторые компоненты должны иметь приоритет независимо от того, когда они были добавлены в сущность (это ответило бы и на ваш другой вопрос).
Я также собираюсь предположить, что мы используем коммуникацию на основе сообщений (ради обсуждения, это просто абстракция по сравнению с вызовом метода на данный момент).
Когда компонент щита «установлен», обработчики сообщений компонента щита связываются с определенным (более высоким) порядком.
Компонент «stats» устанавливает обработчик сообщений «повреждение» по индексу In / Invariant / Normal. Каждый раз, когда получено сообщение «повреждение», уменьшайте HP на величину «стоимости».
Довольно стандартное поведение (добавить некоторую естественную устойчивость к урону и / или расовые черты, что угодно).
Компонент защиты устанавливает обработчик сообщений «повреждение» по индексу In / Pre / High.
Вы можете видеть, что это довольно гибко, хотя это потребует тщательного планирования при проектировании взаимодействия компонентов, так как вам нужно будет определить, в какой части конвейера обработки сообщений установлены обработчики сообщений компонента.
Имеет смысл? Дайте мне знать, если я могу добавить больше деталей.
Редактировать: относительно нескольких экземпляров компонентов (два компонента брони). Вы можете либо отслеживать общее количество экземпляров только в одном экземпляре объекта (однако это убивает состояние каждого компонента) и просто продолжать добавлять обработчики событий сообщений, либо убедиться, что ваши контейнеры компонентов заранее допускают дублирование типов компонентов.
источник
Возможно, зависит от того, насколько многократно вы хотите, чтобы ваш код был и имеет ли он смысл.
Нет, если только этот щит не является каким-то существом, которое может ходить независимо на каком-то этапе.
Это очень похоже на сущность, поэтому ответ - нет.
Это вероятно.
источник
Щит, как физическое существо, ничем не отличается от любого другого физического существа, например, беспилотника, который вращается вокруг вас (и который на самом деле сам может быть типом щита!). Поэтому сделайте щит отдельной логической сущностью (что позволит ему содержать собственные компоненты).
Дайте вашему щиту пару компонентов: физический / пространственный компонент, представляющий форму столкновения, и компонент DamageAffector, который содержит ссылку на некоторую сущность, к которой он будет применять увеличенный или уменьшенный урон (например, персонажа вашего игрока) каждый раз, когда сущность удерживая DamageAffector получает урон. Таким образом, ваш игрок получает урон "по доверенности".
Установите положение объекта щита на положение игрока каждый тик. (Напишите класс компонента многократного использования, который делает это: пишите один раз, используйте много раз.)
Вам нужно будет создать щит, например. на сбор бонусов. Я использую общую концепцию, называемую Emitter, которая представляет собой тип компонента сущности, который порождает новые сущности (обычно через использование EntityFactory, на которую он ссылается). Где вы решите определить местонахождение источника, зависит от вас, например. включите его и включите, когда он будет собран.
Существует тонкая грань между логическими подкомпонентами (Spatial, AI, Слоты с оружием, обработка ввода и т. Д. И т. Д.) И физическими подкомпонентами. Вам нужно решить, на какой стороне вы стоите, так как это сильно определяет, какая у вас система сущностей. Для меня подкомпонент Физики моей сущности управляет физически-иерархическими отношениями (такими как конечности в теле - думайте узлы графа сцены), в то время как логические контроллеры, отмеченные выше, как правило, представлены компонентами вашей сущности, а не представляют индивидуальные физические "приспособления".
источник
Может быть, не содержит других компонентов, но контролирует срок службы вспомогательных компонентов. Так что в некотором грубом псевдокоде ваш клиентский код добавил бы этот «щитовой» компонент.
источник
this
значит в вашем ответе. Имеется вthis
виду компонент Shield или вы имели в виду сущность, которая использует щит, его родителя? Путаница может быть моей ошибкой. «Компонент на основе» является довольно расплывчатым. В моей версии сущностей, основанных на компонентах, сущность - это просто контейнер компонентов с некоторыми минимальными функциональными возможностями (имя объекта, теги, обмен сообщениями и т. Д.).gameObject
или что-то. Это ссылка на текущий игровой объект / сущность / все, что владеет компонентами.Если ваша система компонентов позволяет создавать сценарии, компонент Shield может быть почти суперкомпонентом, который просто вызывает сценарий для своего параметра «эффекта». Таким образом вы поддерживаете простоту отдельного компонента для щитов и освобождаете всю логику того, что он на самом деле делает, с пользовательскими файлами сценариев, которые передаются на щиты вашими определениями сущностей.
Я делаю нечто подобное для моего компонента Moveable, он создает поле со сценарием ключевой реакции (подкласс сценария в моем движке), этот сценарий определяет метод, который следует за моим входным сообщением. как таковой, я могу просто сделать что-то подобное в моем файле определения tempalte
затем в моем перемещаемом компоненте во время регистрации сообщения я регистрирую метод Do сценариев (код на C #)
конечно, это зависит от моего метода Do, следующего за шаблоном функций, которые принимает мой RegisterHandler. В этом случае его (отправитель IComponent, аргумент типа ref)
так что мой «скрипт» (в моем случае также C # только скомпилированный runime) определяет
и мой базовый класс KeyReactionScript
затем позже, когда компонент ввода отправляет сообщение типа MessageTypes.InputUpdate с типом как таковым
Метод в сценарии, который был связан с этим сообщением и типом данных, будет запущен и будет обрабатывать всю логику.
Код довольно специфичен для моего движка, но логика должна быть функциональной в любом случае. Я делаю это для многих типов, чтобы структура компонентов была простой и гибкой.
источник