在游戏子系统中注册游戏对象组件? (基于组件的游戏对象设计)

Posted

技术标签:

【中文标题】在游戏子系统中注册游戏对象组件? (基于组件的游戏对象设计)【英文标题】:Register Game Object Components in Game Subsystems? (Component-based Game Object design) 【发布时间】:2011-04-26 21:15:28 【问题描述】:

我正在创建一个component-based game object system。一些提示:

    GameObject 只是Components 的列表。 有GameSubsystems。例如,渲染、物理等。每个GameSubsystem 都包含指向Components 的一些指针。 GameSubsystem 是一个非常强大和灵活的抽象:它代表游戏世界的任何部分(或方面)。

需要一种在GameSubsystems 中注册Components 的机制(当GameObject 被创建和组合时)。有 4 种方法


1:Chain of responsibility 模式。每个Component 都提供给每个GameSubsystemGameSubsystem 决定注册哪个 Components(以及如何组织它们)。例如,GameSubsystemRender 可以注册 Renderable Components。

专业版。 Components 对它们的使用方式一无所知。低耦合。 A. 我们可以添加新的GameSubsystem。例如,让我们添加注册所有 ComponentTitle 并保证每个标题都是唯一的 GameSubsystemTitles,并提供按标题查询对象的接口。当然,在这种情况下不应重写或继承 ComponentTitle。 B. 我们可以重组现有的GameSubsystems。例如,GameSubsystemAudio、GameSubsystemRender、GameSubsystemParticleEmmiter 可以合并到 GameSubsystemSpatial 中(将所有音频、emmiter、render Components 放在同一层次结构中并使用父级相对变换)。

con。每次检查。非常低效。

con。 Subsystems了解Components


2:每个Subsystem 搜索特定类型的Components

专业版。性能优于Approach 1

con。 Subsystems 还知道Components


3:ComponentGameSubsystem(s) 中注册自己。我们在编译时知道有一个 GameSubsystemRenderer,所以让我们 ComponentImageRender 将调用类似 GameSubsystemRenderer::register(ComponentRenderBase*).Observer 模式。 Component 订阅“更新”事件(由GameSubsystem(s) 发送)。

专业版。表现。无需像 Approach 1Approach 2 那样进行不必要的检查。

con。 ComponentsGameSubsystems 严重耦合。


4:Mediator 模式。 GameState(包含GameSubsystems)可以实现registerComponent(Component*)。

专业版。 ComponentsGameSubystems 对彼此一无所知。

con。在 C++ 中,它看起来像丑陋而缓慢的 typeid-switch。


问题: 哪种方法更好并且主要用于基于组件的设计?实践说什么?关于Approach 4 的(数据驱动的)实现有什么建议吗?

谢谢。

【问题讨论】:

【参考方案1】:

我的方法是在每个子系统中实现代理模式。由于每个子系统只对每个实体可能包含的全部组件的一个子集感兴趣,代理存储指向系统只关心的组件的指针,例如,运动系统只关心位置和速度,因此它需要一个代理来存储两个指针,指向这些组件。如果实体缺少其中一个或多个,则子系统将忽略它。如果两个组件都存在,则创建代理节点并将其添加到内部集合中。代理存储实体的唯一标识符值也很有用,以便在必要时可以在恒定时间内从每个子系统中添加/删除代理。

以这种方式,如果需要从引擎中删除实体,则可以将包含实体 id 的单个消息发送到每个子系统。然后可以独立地从每个子系统集合中删除代理。

【讨论】:

【参考方案2】:

投票支持第三种方法。

我目前正在研究基于组件的游戏对象系统,我清楚地看到了这种方法的一些额外优势:

组件越来越成为自给自足的子实体,因为它仅依赖于一组可用的子系统(我认为这组子系统在您的项目中是固定的)。

数据驱动设计更适用。理想情况下,您可以设计一个系统,其中组件完全用数据定义,而不是 C++。


编辑:我在开发 CGBOS 时想到的一个功能。有时,拥有设计和构造无子系统无源组件的能力会很方便。当您想到这一点时,第四种方法是唯一的方法。

【讨论】:

我同意你的观点,这些优势非常有价值。但第一个有另一面:项目之间没有Component 的可重用性(使用不同的Subsystems 集)。在单个项目中重新组合子系统也成为一个问题。可能有数百个Components,全部重写是一项繁琐的任务。我相信第二个优势也可以通过其他方法实现。 同意你的观点。有一次,我被介绍的 CGBOS 设计并不像我希望的那样多。但是我遇到的处理这个问题的工作让我想到了以下几点:1. 以最抽象的方式设计子系统接口,以便子系统集在不同的项目中会略有变化。 2. 优先考虑组件之间的消息交互,并尽可能减少接口依赖。 可以解决的。我在 gamedev.net 论坛上也遇到了使用这种方法的人。 关于“无子系统无源元件”。我发现将Components 划分为 3 个不同的层次结构非常有用:模型、视图、控制器。 ModelComponent - 只包含数据和一些有用的例程。 (例如问题中提到的 ComponentTitle ) ControllerComponent 具有方法更新并在每个循环中执行某些操作。 ViewComponents - 用于渲染、音频等。有 3 种对应的 Subsystem 类型。我们在编译时就知道在GameObject 中搜索的是哪种Component,因此搜索速度提高了3 倍。我们实现了更好的分解。 对组件分解没有这样的想法。它一定很有价值。

以上是关于在游戏子系统中注册游戏对象组件? (基于组件的游戏对象设计)的主要内容,如果未能解决你的问题,请参考以下文章

提高基于组件的游戏引擎的效率

Unity编程入门2 地形系统和游戏对象

在运行时将一个游戏对象组件添加到另一个具有值的游戏对象中

游戏开发中的基于组件的架构

Unity物理组件之刚体Rigidbody

《游戏引擎架构》笔记十四