(я предлагаю, чтобы проект был игрой или чем-то близким к ней)
Я не предлагаю вам сделать все члены статичными.Основная проблема в том, что вы теряете контроль над временем жизни объекта.Вы не можете легко уничтожить и создать новый объект во время выполнения, потому что нет объекта.Например, если вы хотите сменить менеджера во время выполнения, вам придется внедрить код очистки вручную.В случае объектов C ++ C ++ помогает вам с ошибками / предупреждениями, значениями по умолчанию и членами класса по значению.
Существует несколько популярных способов реализации и использования менеджеров в gamedev:
- ИспользованиеСинглтонВ этом случае у класса есть один статический метод, который возвращает ссылку на нестатический объект.
- Передайте зависимости, которые метод требует при вызове метода вручную.
Шаблон синглтона Я думаю, для вас это лучший способ с точки зрения соотношения цены и качества.Несмотря на всю критику этого шаблона, он хорошо работает (в большинстве игровых проектов, которые я видел, использовался подход Singleton для реализации классов менеджера).
Есть одна важная вещь, которую я хотел бы предложить вам об этом шаблоне.Не используйте стандартную реализацию шаблона Singleton.Создайте методы для создания и уничтожения объекта вместо того, чтобы скрывать его внутри геттера.Вот простой пример связующего кода для менеджера:
class Manager {
private:
static Manager* ms_manager;
public:
static void CreateManager() { ms_manager = new Manager(); }
static void DestroyManager() { delete ms_manager; }
static Manager* GetInstance() { return ms_manager; }
};
Использование:
Manager::GetInstance()->SomeMethod();
Подход с передачей зависимостей имеет свои преимущества.Это может показаться слишком сложным, чтобы передать все в каждом методе обновления, но это не так.Вы можете создать контекстный класс, установить там все зависимости и передать его каждому методу, который в этом нуждается.Это почти как ваш класс World, но это должна быть структура с минимумом кода и без зависимостей.Не храните игровые объекты по значению (только примитивы, векторы геометрии и тому подобное).Это может быть что-то вроде этого:
struct Context {
EntityManager* entityManager;
ComponentManager<PositionComponent>* componentManager;
MovementSystem* movementSystem;
Entity* rootEntity;
};
Использование:
GameObject::Update(Context& context) { context.entityManager->SomeMethod(); }
Суть этого подхода в том, что вы можете настроить контекст для некоторых объектов во время выполнения.Например, если у вас есть LOD, вы можете сохранить в контексте текущий уровень LOD и изменить его во время выполнения для некоторых объектов, в зависимости от расстояния до камеры.