Я работаю над системой компонентов сущностей в C ++, которая, я надеюсь, будет следовать стилю Artemis (http://piemaster.net/2011/07/entity-component-artemis/), так как компоненты в основном представляют собой пакеты данных, и это Системы, содержащие логику. Я надеюсь использовать преимущества этого подхода, ориентированного на данные, и создать несколько хороших инструментов для работы с контентом.
Тем не менее, я сталкиваюсь с одним затруднением в том, как взять некоторую строку идентификатора или GUID из файла данных и использовать его для создания компонента для сущности. Очевидно, я мог бы просто иметь одну большую функцию разбора:
Component* ParseComponentType(const std::string &typeName)
{
if (typeName == "RenderComponent") {
return new RenderComponent();
}
else if (typeName == "TransformComponent") {
return new TransformComponent();
}
else {
return NULL:
}
}
Но это действительно ужасно. Я намерен часто добавлять и изменять компоненты, и, надеюсь, создать какой-то ScriptedComponentComponent, чтобы вы могли реализовать компонент и систему в Lua для целей создания прототипов. Я хотел бы иметь возможность написать класс, унаследованный от некоторого BaseComponent
класса, возможно, добавить пару макросов, чтобы все работало, и затем иметь класс, доступный для реализации во время выполнения.
В C # и Java это было бы довольно просто, так как у вас есть хорошие API отражения для поиска классов и конструкторов. Но я делаю это на C ++, потому что хочу повысить свой уровень владения этим языком.
Итак, как это достигается в C ++? Я читал о включении RTTI, но, похоже, большинство людей настороженно относится к этому, особенно в ситуации, когда мне это нужно только для подмножества типов объектов. Если мне нужна нестандартная система RTTI, где я могу начать изучать ее?
источник
Ответы:
Комментарий:
реализация Artemis интересна. Я придумал подобное решение, за исключением того, что назвал свои компоненты «Атрибуты» и «Поведения». Такой подход разделения типов компонентов работал очень хорошо для меня.
Относительно решения:
код прост в использовании, но его реализация может быть затруднена, если у вас нет опыта работы с C ++. Так...
Желаемый интерфейс
Я сделал центральное хранилище всех компонентов. Каждый тип компонента сопоставляется с определенной строкой (которая представляет имя компонента). Вот как вы используете систему:
Реализация
Реализация не так уж и плоха, но все же довольно сложна; это требует определенных знаний о шаблонах и указателях функций.
Примечание: Джо Вершниг высказал несколько хороших замечаний в комментариях, в основном о том, как моя предыдущая реализация сделала слишком много предположений о том, насколько хорош компилятор в оптимизации кода; проблема не была пагубной, но, тем не менее, меня это тоже беспокоило. Я также заметил, что предыдущий
COMPONENT_REGISTER
макрос не работает с шаблонами.Я изменил код, и теперь все эти проблемы должны быть исправлены. Макрос работает с шаблонами, и проблемы, поднятые Джо, были устранены: теперь компиляторам намного проще оптимизировать ненужный код.
Компонент / component.h
Компонент / detail.h
Компонент / component.cpp
Расширение с Lua
Я должен отметить, что немного поработав (это не очень сложно), это можно использовать для беспроблемной работы с компонентами, определенными в C ++ или Lua, без необходимости думать об этом.
источник
shared_ptr
, но ваш совет все еще хорош.Кажется, что вы хотите, это фабрика.
http://en.wikipedia.org/wiki/Factory_method_pattern
Что вы можете сделать - это зарегистрировать различные компоненты на фабрике, какому имени они соответствуют, а затем у вас есть некоторая карта строкового идентификатора с сигнатурой метода конструктора для генерации ваших компонентов.
источник
Component
классах, вызываяComponentSubclass::RegisterWithFactory()
, верно? Есть ли способ настроить это сделать это более динамично и автоматически? Рабочий процесс, который я ищу: 1. Напишите класс, просматривая только соответствующий заголовок и файл cpp 2. Перекомпилируйте игру 3. Запустите редактор уровней и новый класс компонентов доступен для использования.Некоторое время я работал с дизайном Пола Манты из выбранного ответа и в конечном итоге пришел к этой более общей и краткой фабричной реализации, приведенной ниже, которой я готов поделиться для всех, кто придет к этому вопросу в будущем. В этом примере каждый объект фабрики является производным от
Object
базового класса:Статический класс Factory выглядит следующим образом:
Макрос для регистрации подтипа
Object
выглядит следующим образом:Теперь использование выглядит следующим образом:
Возможность для многих идентификаторов строк для каждого подтипа была полезна в моем приложении, но ограничение на один идентификатор для каждого подтипа было бы довольно простым.
Я надеюсь, что это было полезно!
источник
Основываясь на ответе @TimStraubinger , я создал фабричный класс, используя стандарты C ++ 14, которые могут хранить производные члены с произвольным числом аргументов . Мой пример, в отличие от Тима, использует только одно имя / ключ для каждой функции. Как и у Тима, каждый сохраняемый класс является производным от базового класса, а мой называется Base .
Base.h
EX_Factory.h
main.cpp
Выход
Я надеюсь, что это поможет людям, которым нужно использовать проект Factory, для работы которого не требуется конструктор идентификаторов. Это было забавное проектирование, поэтому я надеюсь, что это поможет людям, нуждающимся в большей гибкости при проектировании на фабрике .
источник