Я пытаюсь разобраться с компонентным дизайном сущностей.
Моим первым шагом было создание различных компонентов, которые можно было бы добавить к объекту. Для каждого типа компонента у меня был менеджер, который вызывал бы функцию обновления каждого компонента, передавая такие вещи, как состояние клавиатуры и т. Д. По мере необходимости.
Следующее, что я сделал, это удалил объект, и у каждого компонента был свой идентификатор. Таким образом, объект определяется компонентами, имеющими одинаковые идентификаторы.
Теперь я думаю, что мне не нужен менеджер для всех моих компонентов, например, у меня есть SizeComponent
, который просто имеет Size
свойство). В результате SizeComponent
метод обновления не имеет, а метод обновления менеджера ничего не делает.
Моей первой мыслью было создать ObjectProperty
класс, к которому компоненты могут обращаться, вместо того, чтобы иметь их как свойства компонентов. Таким образом, объект будет иметь число ObjectProperty
и ObjectComponent
. Компоненты будут иметь логику обновления, которая запрашивает у объекта свойства. Менеджер будет управлять вызовом метода обновления компонента.
Мне это кажется чрезмерной разработкой, но я не думаю, что смогу избавиться от компонентов, потому что мне нужен способ, чтобы менеджеры знали, для каких объектов нужна какая логика компонента (иначе я бы просто удалил компонент полностью и запихни свою логику обновления в менеджер).
- Это (имея
ObjectProperty
,ObjectComponent
иComponentManager
классы) сверхинжиниринг? - Что было бы хорошей альтернативой?
источник
SizeComponent
излишне - вы можете предположить, что большинство объектов имеют размер - это такие вещи, как рендеринг, ИИ и физика, где используется компонентная модель; Размер всегда будет вести себя одинаково - так что вы можете поделиться этим кодом.RenderingComponent
и aPhysicsComponent
. Я слишком обдумываю решение о том, где разместить недвижимость? Должен ли я просто вставить его в один, а затем запросить другой объект для компонента, который имеет необходимое свойство?PhysicalStateInstance
(по одному на объект) вместе сGravityPhysicsShared
(по одному на игру); однако я испытываю желание сказать, что это входит в сферу эйфории архитекторов, не создавайте себе дыру (именно то, что я сделал с моей первой компонентной системой). ПОЦЕЛУЙ.Ответы:
Простой ответ на ваш первый вопрос: да, вы перешли к разработке дизайна. «Как далеко я ломаю вещи?» Вопрос очень часто встречается, когда делается следующий шаг и центральный объект (обычно называемый сущностью) удаляется.
Когда вы разбиваете объекты на такой детальный уровень, чтобы иметь размеры сами по себе, тогда дизайн заходит слишком далеко. Значение данных само по себе не является компонентом. Это встроенный тип данных, который часто можно назвать именно тем, что вы начали называть, свойством. Свойство не является компонентом, но компонент содержит свойства.
Итак, вот несколько рекомендаций, которым я стараюсь следовать при разработке в системе компонентов:
Таким образом, с учетом того, что компоненты не являются структурами, SizeComponent был разбит слишком далеко. Он содержит только данные, и то, что определяет размер чего-либо, может варьироваться. Например, в компоненте рендеринга это может быть 1d-скаляр или 2 / 3d-вектор. В физическом компоненте это может быть ограничивающий объем объекта. В инвентаре это может быть количество места, которое занимает 2D-сетка.
Попробуйте провести хорошую грань между теорией и практичностью.
Надеюсь это поможет.
источник
Вы уже приняли ответ, но вот мой удар в CBS. Я обнаружил, что у общего
Component
класса есть некоторые ограничения, поэтому я выбрал дизайн, описанный Radical Entertainment на GDC 2009, который предложил разделить компоненты наAttributes
иBehaviors
. (« Теория и практика архитектуры компонентов игровых объектов », Марчин Чады)Я объясняю свои дизайнерские решения в двухстраничном документе. Я просто выложу ссылку, так как здесь слишком долго вставлять все это. В настоящее время он охватывает только логические компоненты (но не компоненты рендеринга и физики), но он должен дать вам представление о том, что я пытался сделать:
► http://www.pdf-archive.com/2012/01/08/entity-component-system/preview/page/1
Вот выдержка из документа:
Изменить: И вот диаграмма отношений, которая показывает, как компоненты взаимодействуют друг с другом:
Детали реализации: уровень сущности
EventManager
создается, только если он используется.Entity
Класс просто хранит указатель наEventManager
который инициализируется только если некоторые запросы компонента его.Изменить: На другой вопрос я дал аналогичный ответ на этот вопрос. Вы можете найти его здесь для, возможно, лучшего объяснения системы:
► /gamedev//a/23759/6188
источник
Это действительно зависит от свойств, которые вам нужны и где вы нуждаетесь в них. Объем памяти, который у вас будет, и мощность / тип обработки, которые вы будете использовать. Я видел и пытаюсь сделать следующее:
Эти принципы имеют свои ограничения. Конечно, вам придется передать геометрию в рендерер, но вы, вероятно, не захотите получить ее оттуда. Основная геометрия будет сохранена в физическом движке в случае, если там происходят деформации и синхронизируются с рендерером (время от времени в зависимости от расстояния объектов). Таким образом, вы все равно продублируете его.
Там нет идеальных систем. И некоторые игры будут лучше с более простой системой, в то время как другие потребуют более сложной синхронизации между системами.
Сначала убедитесь, что ко всем свойствам можно легко получить доступ из ваших компонентов, чтобы вы могли изменить способ прозрачного хранения свойств после того, как начнете тонкую настройку ваших систем.
Нет ничего постыдного в копировании некоторых свойств. Если нескольким компонентам необходимо хранить локальную копию, иногда более эффективно копировать и синхронизировать, а не обращаться к «внешнему» значению »
Также синхронизация не должна происходить каждый кадр. Некоторые компоненты могут быть синхронизированы реже, чем другие. Компонент рендеринга часто является хорошим примером. Те, кто не взаимодействует с игроками, могут синхронизироваться реже, как и те, которые находятся далеко. Те, кто находится далеко от поля камеры, могут синхронизироваться еще реже.
Когда дело доходит до вашего компонента размера, он может быть связан с вашим компонентом позиции:
Вместо размера вы могли бы даже использовать модификатор размера, это может пригодиться.
Что касается хранения всех свойств в общей системе хранения свойств ... Я не уверен, что вы движетесь в правильном направлении ... Сосредоточьтесь на свойствах, которые являются ключевыми для вашей игры, и создайте компоненты, которые объединяют как можно больше связанных свойств. Если вы правильно абстрагируете доступ к этим свойствам (например, через геттеры в компонентах, которые в них нуждаются), вы сможете перемещать, копировать и синхронизировать их позже, не нарушая слишком много логики.
источник
Если компоненты могут быть произвольно добавлены к объектам, то вам нужен способ запросить, существует ли данный компонент в объекте, и получить ссылку на него. Таким образом, вы можете перебирать список объектов, полученных из ObjectComponent, пока не найдете нужный объект и не вернете его. Но вы бы вернули объект правильного типа.
В C ++ или C # это обычно означает, что у вас будет такой же шаблонный метод для сущности
T GetComponent<T>()
. И когда у вас есть эта ссылка, вы точно знаете, какие данные он содержит, поэтому просто обращайтесь к ней напрямую.В чем-то вроде Lua или Python вы не обязательно имеете явный тип этого объекта, и, вероятно, вам тоже все равно. Но опять же, вы можете просто получить доступ к переменной-члену и обработать любое исключение, возникающее при попытке получить доступ к тому, чего там нет.
Запрос свойств объекта явно напоминает дублирование работы, которую язык может сделать для вас, либо во время компиляции для статически типизированных языков, либо во время выполнения для динамически типизированных.
источник
Дело в том, что RenderingComponent использует позицию, но PhysicsComponent предоставляет ее. Вам просто нужен способ сообщить каждому пользовательскому компоненту, какой поставщик использовать. В идеале агностиком, иначе будет зависимость.
Там нет общего правила. Зависит от конкретного свойства (см. Выше).
Создайте игру с уродливой, но основанной на компонентах архитектурой, а затем проведите ее рефакторинг.
источник
PhysicsComponent
делать тогда. Я рассматриваю это как управление имитацией объекта в физической среде, что приводит меня к путанице: не все вещи, которые нужно визуализировать, нужно будет имитировать, поэтому мне кажется неправильным добавлять ихPhysicsComponent
при добавлении,RenderingComponent
поскольку они содержат позицию которыйRenderingComponent
использует. Я мог легко видеть, что я заканчиваю сетью взаимосвязанных компонентов, означая, что все / большинство должно быть добавлено к каждой сущности.Ваша кишка рассказывает вам , что имея
ThingProperty
,ThingComponent
иThingManager
для каждогоThing
типа компонента немного избыточна. Я думаю, что это правильно.Но вам нужен какой-то способ отслеживать связанные компоненты с точки зрения того, какие системы их используют, к какому объекту они принадлежат и т. Д.
TransformProperty
будет довольно распространенным. Но кто за это отвечает, система рендеринга? Физическая система? Звуковая система? ЗачемTransform
компоненту даже нужно обновлять себя?Решение состоит в том, чтобы удалить любой код из ваших свойств, кроме геттеров, сеттеров и инициализаторов. Компоненты - это данные, которые используются игровыми системами для выполнения различных задач, таких как рендеринг, AI, воспроизведение звука, движение и т. Д.
Читайте об Артемисе: http://piemaster.net/2011/07/entity-component-artemis/
Посмотрите на его код, и вы увидите, что он основан на системах, которые объявляют свои зависимости в виде списков
ComponentTypes
. Вы пишете каждый из своихSystem
классов и в методе constructor / init объявляете, от каких типов зависит эта система.Во время настройки уровней или еще чего-то вы создаете свои сущности и добавляете к ним компоненты. После этого вы говорите этой сущности отчитаться перед Артемидой, и тогда Артемида выясняет, исходя из состава этой сущности, какие системы будут заинтересованы знать об этой сущности.
Затем на этапе обновления вашего цикла у вас
System
теперь есть список объектов, которые нужно обновить. Теперь вы можете иметь детализацию компонентов , так что вы можете разработать бредовые системы, строить объекты изModelComponent
,TransformComponent
,FliesLikeSupermanComponent
, иSocketInfoComponent
, и сделать что - то странное , как макияж летающая тарелка , которая летит между клиентами подключены к многопользовательской игре. Ладно, может быть и не так, но идея в том, что он делает вещи разъединенными и гибкими.Артемида не идеальна, и примеры на сайте немного просты, но разделение кода и данных является мощным. Это также хорошо для вашего кэша, если вы делаете это правильно. Артемида, вероятно, не делает этого прямо на этом фронте, но учиться хорошо.
источник