2016-02-21 7 views
2

Я пишу игру на C++ с использованием OpenGL и решил написать компонентную систему, похожую на Unity или Unreal Engine - для развлечения и чтобы узнать, как эти системы созданы/работают. Я дошел до того, что мне нужно реализовать Компоненты и GameObjects, которые я сделал довольно успешно.C++ Сокращение использования указателей, необработанных или других и/или возвращающих нулевых не указателей

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

Примеры:

GetComponent<MeshRenderer>(); //Returns "MeshRenderer" Component as MeshRenderer* 
AddComponent(new MeshRenderer(mesh)); //Adds component to vector + returns MeshRenderer* 

компоненты являются рефераты классы и расширены компонентами, такими как MeshRenderer.

T *AddComponent(T *component) 
{ 
    component->parent = this; 
    m_components[typeid(T).name()] = component; 

    bool pushLocation = true; 
    for (unsigned int i = 0; i < m_component_locations.size(); i++) 
     if (m_component_locations.at(i) == typeid(T).name()) 
      pushLocation = false; 
    if(pushLocation) 
     m_component_locations.push_back(typeid(T).name()); 
    return GetComponent<T>(); 
} 

Выше: My AddComponent(); Код, используемый для добавления компонентов - требуется указатель на компонент ...

std::unordered_map<std::string, Component*> m_components; //Holds the components 
std::vector<std::string> m_component_locations; //Holds data on components, allows them to be indexed 

Выше: Как хранить свои компоненты в классе геймобжекты, позволяет мне перебрать их по индексу

Мои проблемы с этот подход связан с тем, как я реализовал функцию GetComponent(). Он возвращает указатель на компонент и, возможно, nullptr, если такой компонент не существует.

T *GetComponent() 
{ 
    if (m_components.count(typeid(T).name()) != 0) 
    { 
     return static_cast<T*>(m_components[typeid(T).name()]); 
    } 
    else 
    { 
     return nullptr; 
    } 
} 

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

Я сделал переменные private, и GameObject обрабатывает удаление компонентов, и я бы предпочел не позволять себе удалять что-либо из-за некомпетентности или тому подобного.

Я думал о возврате unique_ptr, но я не уверен, будет ли эта реализация предпочтительной.

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

+0

'typeid (T) .name()' вы не должны полагаться на это каким-либо образом, используйте его только для целей отладки, так как нет никаких гарантий относительно того, что именно это делает –

+0

Хорошо, есть ли у вас какие-либо предложения по как я мог бы изменить его для одного и того же использования, но не полагаясь на 'typeid (t) .name()'? –

+0

Вы можете использовать хеш-код или 'std :: type_index', см. Там в примечаниях: http://en.cppreference.com/w/cpp/language/typeid –

ответ

1

Ваша идея сокращения использования сырья указателей является правильным. Я думаю, вы должны посмотреть в EntityX library и заметить, как все реализовано. Здесь нет указателей.

Для вашего случая вам нужно сделать то же самое, что и EntityX - создать класс ComponentHandle со ссылкой (не указателем) на ваш компонент. Этот класс не управляет жизненным циклом вашего компонента. Это просто интерфейс для вашего компонента. Вы также можете перегрузить оператор -> для доступа к членам вашего компонента.

Удачи вам в C++ и компоненте-сущности-системе.

+1

Решение EntityX - это именно то, что мне нужно, спасибо. –

+0

@Freak_ey Это похоже на 'std :: reference_wrapper', возможно, вам тоже понравится. –