【问题标题】:Component based game engine design [closed]基于组件的游戏引擎设计
【发布时间】:2010-12-26 10:53:08
【问题描述】:

我一直在研究游戏引擎设计(特别关注 2d 游戏引擎,但也适用于 3d 游戏),并且对有关如何进行它的一些信息感兴趣。我听说现在许多引擎正在转向基于组件的设计,而不是传统的深层对象层次结构。

您是否知道任何有关此类设计通常如何实施的信息的良好链接?我看过evolve your hierarchy,但我真的找不到更多详细信息(他们中的大多数似乎只是说“使用组件而不是层次结构”,但我发现转换我的想法需要一些努力两个模型之间)。

任何好的链接或信息都将受到赞赏,甚至书籍,尽管此处的链接和详细答案将是首选。

【问题讨论】:

    标签: architecture game-engine entity-component-system entity-system


    【解决方案1】:

    2013-01-07 更新如果您想看到基于组件的游戏引擎与(在我看来)卓越的反应式编程方法的完美结合,请查看V-Play engine。它很好地集成了 QTs QML property binding 功能。

    我们在大学里对游戏中的 CBSE 进行了一些研究,这些年来我收集了一些材料:

    游戏文学中的 CBSE:

    • 游戏引擎架构
    • Game Programming Gems 4:管理游戏实体游戏的系统
    • 游戏编程宝典5:基于组件的对象管理
    • Game Programming Gems 5:通用组件库
    • 游戏编程宝典6:游戏对象组件系统
    • 面向对象的游戏开发
    • Architektur des Kerns einer Game-Engine und Implementierung mit Java(德语)

    Elephant game framework 是 C# 中基于组件的游戏引擎的一个非常好的和干净的示例。

    如果您真的想知道阅读了哪些组件:基于组件的软件工程! 他们将组件定义为:

    软件组件是符合组件模型的软件元素,可以根据组合标准独立部署和组合,无需修改。

    组件模型 定义特定的交互和组合标准。 组件模型实现是支持执行符合模型的组件所需的专用可执行软件元素集。

    软件组件基础架构是一组交互的软件组件,旨在确保使用这些组件和接口构建的软件系统或子系统将满足明确定义的性能规范。

    经过 2 年的游戏 CBSE 经验,我认为面向对象编程只是一条死胡同。记住我的警告,当你看到你的组件变得越来越小,更像是封装在组件中的函数,有很多无用的开销。请改用functional-reactive programming。还可以看看我关于 Why I switched from component-based game engine architecture to FRP 的新博客文章(在写这篇文章时它让我想到了这个问题:))。

    游戏论文中的 CBSE:

    游戏中的 CBSE 网页链接(按相关性排序):

    【讨论】:

    • 我很难在 FRP 上找到与游戏引擎相关的资源。能否提供一些代码或链接?
    • FRP 通常是一个小领域,尤其是在游戏中。存在多年,但仍然相当前沿。如果您搜索与 Haskell 语言相关的函数式反应式编程,您会发现大部分关于它的研究。重点项目是 Fruit、Fran 和 Yampa。 Yampa Arcade 是一篇描述在游戏中使用 Yampa 反应库的论文。不过,我还没有听说过任何实际的实现,除了一些使用新的 .NET 反应式的 Silverlight 东西。
    • “Elephant 游戏框架是 C# 中基于组件的游戏引擎的一个非常好的和干净的示例。”它从未完成,也没有解决任何现实世界的问题,如组件/实体间通信。
    • 我是 Elephant-thingie 的作者,在任何人决定使用这个旧东西之前,我想指出我已经发布了一个名为 ComponentKit 的替代方案。虽然它没有提供任何与游戏相关的内容,但它至少是关于如何实现这样一个系统的有用参考。
    • 我把它读成“软件组件就是软件大象”..太累了
    【解决方案2】:

    似乎确实缺乏有关该主题的信息。我最近实现了这个系统,我发现了一个非常好的 GDC Powerpoint,它很好地解释了经常被遗忘的细节。该文件在这里:Theory and Practice of Game Object Component Architecture

    除了那个 Powerpoint,还有some good resourcesvarious blogs。 PurplePwny 有一个很好的讨论和一些其他资源的链接。 Ugly Baby Studios 围绕组件如何相互交互的想法进行了一些讨论。祝你好运!

    【讨论】:

    • 第一个 powerpoint +1,非常发人深省!
    • @Noah: GDC ppt 链接坏了,请问你们其他地方有存货吗? :-)
    • 暂时没有,等我下班我会去挖掘看看我是否在任何地方放置了备份副本。
    • 呵呵,下载了 ppt(链接有效),然后意识到我 5 年前参加了这个演讲,谢谢你的提醒。一般来说,小心不要在你的组件中放置太多的行为,那样会导致意大利面条式的代码和最终的疯狂。支持保存数据的“愚蠢”组件,并将您的行为放入实体处理器中。
    【解决方案3】:

    上学期我研究并实施了一个游戏开发课程。希望此示例代码可以为您指明如何处理此问题的正确方向。

    class Entity {
    public:
        Entity(const unsigned int id, const std::string& enttype);
        ~Entity();
    
        //Component Interface
        const Component* GetComponent(const std::string& family) const;
        void SetComponent(Component* newComp);
        void RemoveComponent(const std::string& family);
        void ClearComponents();
    
        //Property Interface
        bool HasProperty(const std::string& propName) const;
        template<class T> T& GetPropertyDataPtr(const std::string& propName);
        template<class T> const T& GetPropertyDataPtr(const std::string& propName) const;
    
        //Entity Interface
        const unsigned int GetID() const;
        void Update(float dt);
    
    private:
        void RemoveProperty(const std::string& propName);
        void ClearProperties();
        template<class T> void AddProperty(const std::string& propName);
        template<class T> Property<T>* GetProperty(const std::string& propName);
        template<class T> const Property<T>* GetProperty(const std::string& propName) const;
    
        unsigned int m_Id;
        std::map<const string, IProperty*> m_Properties;
        std::map<const string, Component*> m_Components;
    };
    

    组件指定行为并对属性进行操作。属性通过引用在所有组件之间共享,并免费获得更新。这意味着消息传递没有大的开销。如果有任何问题,我会尽力回答。

    【讨论】:

    • 所以你使用组件的属性来相互通信?这种方法不会破坏封装吗?基本上,您将属性用作一堆全局变量。
    • 除了happy_emi 的cmets,您刚刚将“消息传递的大量开销”(我假设您的意思是字符串查找和糟糕的缓存一致性)换成了与属性相关的大量开销。您实现的组件部分看起来不错,但属性部分没有意义 - 要么在你的实体上创建组件可以设置的那些真实字段,要么保留组件间引用。
    • 属性仅在创建组件时查找并存储为指针。获取实体上的“共享”数据需要一次性成本。只有在所有组件都可以访问他们想要的实体上的任何数据的意义上,数据才是“全局的”。我不是在谈论纯粹的字符串查找,还有被调用的额外代码。请记住,您的游戏中可能有大量实体。当你可以让一个组件设置数据时,为每个实体传递一条消息以在每个游戏循环中更新它们的位置是很多无用的开销。
    • 也许举个例子会有所帮助。假设您的实体有一个 Pathing 组件和一个 Rendering 组件,都需要 Vec3 位置。顺序是任意的,但假设首先创建了 Render 组件。 Render 向实体询问 Vec3 位置属性,该属性是在实体上创建的,并将指针提供给 Render。现在 Pathing 被创建,它请求相同的 Vec3 位置,并且实体返回它刚刚创建的属性的指针(实际上是属性内的原始数据)。此时,当 Pathing 更新位置时,Render 可以在不请求新位置数据的情况下进行绘制。
    【解决方案4】:

    我目前正在 GameDev.net 上的许多(很多)线程中研究这个确切的主题,并发现以下两种解决方案是我将为我的游戏开发的很好的候选者:

    【讨论】:

      【解决方案5】:

      它是开源的,可在http://codeplex.com/elephant获得

      有人制作了 gpg6 代码的工作示例,你可以在这里找到它:http://www.unseen-academy.de/componentSystem.html

      或在这里:http://www.mcshaffry.com/GameCode/thread.php?threadid=732

      问候

      【讨论】:

      【解决方案6】:

      虽然不是关于游戏引擎设计主题的完整教程,但我发现this page 有一些关于游戏组件架构使用的很好的细节和示例。

      【讨论】:

        【解决方案7】:

        有趣的文章...

        我在 google 上进行了快速搜索,但一无所获,但您可能想检查一些 cmets - 很多人似乎都尝试过实现一个简单的组件演示,您可能想采取看看他们的一些灵感:

        http://www.unseen-academy.de/componentSystem.html
        http://www.mcshaffry.com/GameCode/thread.php?threadid=732
        http://www.codeplex.com/Wikipage?ProjectName=elephant

        此外,cmets 本身似乎对如何编写这样的系统进行了相当深入的讨论。

        【讨论】:

          【解决方案8】:

          在我看来,在这种情况下,组件听起来像是引擎的独立运行时部分,可以与其他组件同时执行。如果这是动机,那么您可能需要查看actor model 以及使用它的系统。

          【讨论】:

            猜你喜欢
            • 2017-07-27
            • 2012-01-14
            • 2015-04-30
            • 1970-01-01
            • 2018-01-02
            • 1970-01-01
            • 2016-09-21
            • 2011-04-26
            • 1970-01-01
            相关资源
            最近更新 更多