C ++: Проектирование системы сущностей на основе компонентов - сложные проблемы - PullRequest
12 голосов
/ 25 февраля 2011

В моем игровом движке, написанном на C ++, я отошел от классической системы иерархических сущностей и создал компонентную систему.Это работает примерно так:

Сущность - это просто контейнер для компонентов.Некоторые примерные компоненты: Точка, Спрайт, Физика, Излучатель.

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

Так что все работает с системой компонентов, но теперь у меня проблемы с реализацией более специализированных объектов,как:

  • Камера, которой требуются дополнительные функции для управления перемещением и масштабированием
  • Плеер, которому требуется поддержка для получения ввода от пользователя и перемещения

Теперь я мог бы легко решить это с помощью наследования.Просто извлеките камеру из объекта и добавьте дополнительные функции масштабирования и элементы.Но это просто кажется неправильным.

Мой вопрос:

  • Как я могу решить проблему специализированных объектов с компонентной системой в C ++?

Ответы [ 5 ]

14 голосов
/ 25 февраля 2011

Вы, кажется, сомневаетесь в отношениях IS-A здесь. Так почему бы не сделать это отношениями HAS-A? Вместо того, чтобы быть сущностью, камера и проигрыватель могут быть объектами, которые имеют сущность (или ссылку на сущность), но существуют вне вашей системы компонентов. Таким образом, вы можете легко сохранить единообразие и ортогональность вашей компонентной системы.

Это также хорошо согласуется со значением этих двух примеров (камера / плеер) как «склеенные» объекты. Игрок приклеивает систему сущностей к системе ввода и действует как контроллер. Камера приклеивает систему объектов к визуализатору и выступает в роли наблюдателя.

3 голосов
/ 26 февраля 2011

А как насчет создания компонентов, обеспечивающих такое поведение?Например, InputComponent может обрабатывать ввод от игрока.Тогда ваш дизайн остается прежним, и игрок - это просто объект, который позволяет вводить данные с клавиатуры, а не с контроллера AI.

1 голос
/ 26 февраля 2011

Система, основанная на компонентах, обычно имеет общий метод, позволяющий отправлять «сообщения» объектам, например, функцию send(string message_type, void* data). Затем объект передает его всем его компонентам, и только некоторые из них будут реагировать на него. Например, ваш компонент Point может реагировать на send("move", &direction). Или вы можете ввести компонент moveable, чтобы иметь больше контроля. То же самое для вашей камеры, добавьте компонент view и сделайте так, чтобы он обрабатывал сообщение «zoom».

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

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

0 голосов
/ 25 февраля 2011

Распространенным решением является использование шаблона посетителя. По сути, ваша сущность будет «посещаться» классом Visitor. Внутри вашей сущности у вас будет:

void onVisitTime(Visitor* v)
{
   // for each myComponent...
   v->visit(myComponent);
   // end for each
}

И тогда у вас будет в классе Посетитель:

void visit(PointComponent* p);
void visit(CameraComponent* c);

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

0 голосов
/ 25 февраля 2011

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

...