私は OpenGL を使用して C++ でゲームを作成しており、Unity や Unreal Engine によく似たコンポーネント ベースのシステムを作成することに決めました。コンポーネントとゲームオブジェクトを実装する必要がある段階に達しましたが、これは非常にうまくいきました。
私の実装は機能します...それはまさに私が望む方法ではありません。現在、コンポーネントへのポインタのプライベート ベクトルとしてコンポーネントを格納し、要求されたときにコンポーネントを返します。
例:
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>();
}
上: 私の 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
上: コンポーネントを GameObject クラスに格納する方法により、インデックスでそれらをループすることができます
このアプローチに関する私の問題は、GetComponent() 関数をどのように実装したかによるものです。Component へのポインターを返し、そのような Component が存在しない場合は nullptr を返す可能性があります。
T *GetComponent()
{
if (m_components.count(typeid(T).name()) != 0)
{
return static_cast<T*>(m_components[typeid(T).name()]);
}
else
{
return nullptr;
}
}
ここでの問題は、ポインターを返すため、delete を呼び出してポインターを削除できることです。これらは生のポインターですが、GameObject が破棄されたときにプログラムによって処理されるようにしました。(私が無能でない限り) メモリ リークの心配がないことを願っていますが、参照を返すことをお勧めします。それらに対して「削除」を呼び出すことができないという事実-私が犯す可能性のある愚かな間違いを避けるため.
私は変数を非公開にし、GameObject がコンポーネントの削除を処理します。無能などのために何かを削除する機能を自分に許可したくありません。
unique_ptr を返すことを考えましたが、その実装が望ましいかどうかはわかりません。
(追加のメモとして、GetComponent() 関数を使用して何らかの null を返すか、そのようなコンポーネントが存在しないことを示す必要があります)