实体组件系统 - 相互需要的组件

Posted

技术标签:

【中文标题】实体组件系统 - 相互需要的组件【英文标题】:Entity Component System - Components requiring each other 【发布时间】:2018-08-17 01:41:01 【问题描述】:

我为我的游戏 (C++) 编写了一个实体组件系统。然后我重构了我的渲染系统以使用 Entities / RenderComponents 而不是一些虚拟的可绘制界面。它们是一些类,我认为强迫它们成为一个组件没有太大意义。其中一类是地图。

我的地图类包含一个平铺的地形类和一些其他数据(不重要)。平铺地形类以(目前)TiledTerrainLayer 类的形式管理多个图层。在重构渲染系统之前,我只是简单地从DrawableTransformable 继承,以使这个类能够被渲染系统绘制。现在要求它是一个至少有一个TransformComponent 和一些RenderComponent 的实体。

现在,TiledTerrainLayerRenderComponent 应该只拥有顶点和纹理的引用,也许还有一个标志是否已经创建。然后,TiledTerrainComponent 将拥有图块缺陷列表以及图块和地图大小。

现在我的问题是,当我设置图块时(使用类似SetTile(size_t tileIndex, const Position & pos) 的方法,我还必须更新顶点数组的纹理坐标。

我通常对一个需要另一个组件的组件很好。例如,SpriteRenderComponent 需要TransformComponent,我也可以让一个组件访问另一个组件的信息。例如。 GetBoundingBox() 方法使用变换组件的位置。

我要避免的是两个组件相互“交叉引用”,就像 TiledTerrainComponent (TTC) 和 TiledTerrainRenderComponent 的情况一样。 (TTRC) (TTRC 获取 TTC 的 tileIndexList 来创建自己,TTC 在调用其 SetTile() 方法时调用 TTRC 的 UpdateVertices() 方法。

最后,我知道组件应该主要是数据。我只添加了直接获取或修改该数据的方法,例如 SetTile() 或 GetTexture()。在上述情况下,系统是否可行?如果可行,它会是什么样子?

【问题讨论】:

【参考方案1】:

听起来你只需要Dirty Flag。

当您更改平铺地形上的平铺索引、大小或其他属性时,您不会立即调用平铺渲染器来更新其顶点(毕竟,这一帧您可能还有许多平铺更新 - 它可能是每次都重新计算顶点很浪​​费)

相反,Tiled Terrain 渲染器只是将其内部 hasBeenModifiedSinceLastUse 标志设置为 true。它根本不需要知道 Renderer。

接下来,在绘制之前更新您的 Tiled Renderer 时,您可以让它询问其 Tiled Terrain 自上次绘制以来是否已更新(如果您想针对更改,您甚至可以查询更新列表)。如果是这样,您可以批量更新顶点,以获得更好的代码和数据局部性。

在此过程中,您重置修改的标志,以便如果后续帧没有更新,您可以按原样重新使用最后生成的一组顶点。

现在你的依赖点只有一种方式——渲染器依赖于瓦片数据,但是瓦片数据除了维护它的标志之外不知道渲染。

【讨论】:

以上是关于实体组件系统 - 相互需要的组件的主要内容,如果未能解决你的问题,请参考以下文章

vue中同一个页面多次使用同一个组件的相互干扰问题

微服务架构 SpringCloud组件和概念介绍

vue组件之间相互传值的方式

C++:设计基于组件的实体系统——高级问题

实体组件系统c#

vue父子组件相互访问