首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类Unity3D组件系统

类Unity3D组件系统
EN

Code Review用户
提问于 2017-04-14 14:11:48
回答 1查看 552关注 0票数 2

我目前正在开发我自己的小游戏引擎,并考虑实现一个简化版本的Unitys 构件系统,您可以将派生Components的对象附加到GameObject上。稍后,您可以请求特定的Components使用它们的功能。下面是我对实现的一个精简(但仍然有效)版本。

代码语言:javascript
复制
#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是更好的选择。然而,我从来没有使用过动态铸造,我不确定我使用它的方式是否安全,所以请告诉我是吗?

此外,如果您看到任何改进点,我将感谢您的意见。

EN

回答 1

Code Review用户

发布于 2017-04-14 15:54:51

我不是C++程序员,但我注意到有几件事在任何语言中都很重要。

保持一致:

虽然您会发现许多人对不同的命名约定和编码风格充满热情,但他们都会同意的一件事是,至少要在您的选择中保持一致。代码中有一些不一致之处:

  • 您可以声明Component类的私有成员名为parent,然后使用名为m_Components的成员在GameObject类中引入匈牙利符号
  • 您可以在星号:Component * parent;的两边声明一个带有空格的指针,并在构造函数中继续使用该样式,但在其他一些情况下,您也可以将星号连接到类型:GameObject* GetParent()SetParent(GameObject* parent)
  • 在您的GameObject析构函数中,您有一个带有单行体的for,并选择省略大括号,但是在它的AddComponent成员函数中,您有一个带有单行体的if,但是保留了花括号。如果你要省略前者的花括号,你也可以在后者中省略它们。
  • 如果您坚持省略花括号,则前者也可以以更易读的方式编写: for (size_t i= 0;i< m_Components.size();++i) If (m_Components我->GetParent() == this)删除m_Components我;

还:

  • virtual std::string What() { return "Basic Component"; }“什么”不是一个描述性很强的标识符。考虑用类似于"GetName()“的东西替换它
  • 动态转换: component_type* c= dynamic_cast(comp);if (c)返回c;我经常看到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++表示。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/160764

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档