我目前正在开发我自己的小游戏引擎,并考虑实现一个简化版本的Unitys 构件系统,您可以将派生Components的对象附加到GameObject上。稍后,您可以请求特定的Components使用它们的功能。下面是我对实现的一个精简(但仍然有效)版本。
#include <iostream>
#include <vector>
class GameObject;
class Component
{
private:
GameObject * parent;
public:
Component(GameObject * parent = nullptr)
{
this->parent = parent;
}
virtual ~Component() { parent = nullptr; }
GameObject* GetParent() { return parent; }
void SetParent(GameObject* parent) { this->parent = parent; }
virtual std::string What() { return "Basic Component"; }
};
class SoundSource : public Component
{
private:
// some sound specific members
public:
SoundSource(GameObject * parent = nullptr) : Component(parent) {}
virtual ~SoundSource() { }
std::string What() { return "SoundSource Component"; }
};
class GameObject
{
private:
std::vector<Component*> m_Components;
public:
GameObject() :
m_Components()
{}
~GameObject()
{
for (size_t i = 0; i < m_Components.size(); ++i)
if (m_Components[i]->GetParent() == this) delete m_Components[i];
m_Components.clear();
}
void AddComponent(Component* comp)
{
if (comp->GetParent() == nullptr)
{
comp->SetParent(this);
}
m_Components.push_back(comp);
}
template <class component_type>
component_type* GetComponent()
{
for (auto comp : m_Components)
{
component_type* c = dynamic_cast<component_type*>(comp);
if (c) return c;
}
return nullptr;
}
};
int main()
{
GameObject go;
go.AddComponent(new SoundSource());
go.AddComponent(new Component());
SoundSource *s = go.GetComponent<SoundSource>();
if (s) std::cout << s->What() << std::endl;
}我最初的GetComponent<>()计划是使用typeid的名称来比较组件类型,但是由于所有组件都需要从相同的基础派生,我认为在这种情况下使用dynamic_cast是更好的选择。然而,我从来没有使用过动态铸造,我不确定我使用它的方式是否安全,所以请告诉我是吗?
此外,如果您看到任何改进点,我将感谢您的意见。
发布于 2017-04-14 15:54:51
我不是C++程序员,但我注意到有几件事在任何语言中都很重要。
虽然您会发现许多人对不同的命名约定和编码风格充满热情,但他们都会同意的一件事是,至少要在您的选择中保持一致。代码中有一些不一致之处:
Component类的私有成员名为parent,然后使用名为m_Components的成员在GameObject类中引入匈牙利符号。Component * parent;的两边声明一个带有空格的指针,并在构造函数中继续使用该样式,但在其他一些情况下,您也可以将星号连接到类型:GameObject* GetParent()和SetParent(GameObject* parent)。GameObject析构函数中,您有一个带有单行体的for,并选择省略大括号,但是在它的AddComponent成员函数中,您有一个带有单行体的if,但是保留了花括号。如果你要省略前者的花括号,你也可以在后者中省略它们。virtual std::string What() { return "Basic Component"; }“什么”不是一个描述性很强的标识符。考虑用类似于"GetName()“的东西替换它dynamic_cast以这种形式出现,我发现这种形式更易读: if (component_type* c= dynamic_cast(comp))返回c;std::vector。在循环遍历std::vector元素以查找单个元素的任何时候,都应该考虑使用std::map。使用这些数据结构来使用关键对象定位值对象比遍历vector要快得多,因为无论集合中有多少项,它都要花费相同的时间。这种方法将产生一个更快的GetComponent()方法我不确定这是否是在联合中实现GetComponent的方法,但我知道它建议不要在联合中的Update方法中使用GetComponent,因为它有多慢。如果您使用std::map来实现您的GetComponent方法,与预先进行查找和存储结果(这是目前建议的统一方法)相比,这将是一个微小的差别。
这是我对你的面向对象设计的唯一真正的反馈。在大多数情况下,它似乎是统一组件系统相当准确的C++表示。
https://codereview.stackexchange.com/questions/160764
复制相似问题