问题标签 [entity-component-system]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
8 回答
161545 浏览

architecture - 基于组件的游戏引擎设计

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

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

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

0 投票
5 回答
2788 浏览

c++ - 实体组件系统的自定义堆预分配

我有一个 OOP 实体组件系统,目前的工作方式如下:


为了创建新的实体和组件,我使用 C++ 的常用newand delete


该系统运行良好,我喜欢它的语法和灵活性。但是,当不断向管理器添加和删除实体和组件时,内存分配/释放会减慢应用程序的速度。(我已经分析并确定减速是由newand引起的delete)。

我最近读到可以在 C++ 中预先分配堆内存 - 如何将其应用于我的情况?


期望的结果:

0 投票
2 回答
3996 浏览

c++11 - 实体组件系统的设计

我想知道如何用 C++ 实现最快版本的实体组件系统(ECS 从现在开始)。

首先,关于术语:

  • 场景实体(以及某些实现中的系统)的容器
  • 组件是一个简单的数据存储(如位置、碰撞框、要渲染的图像等)
  • 系统对符合系统要求的组件执行逻辑(这可能是物理、玩家输入、简单渲染等)
  • 一个实体包含几个组成最终行为的组件

我在下面列出了我们提出的所有设计。


1.“幼稚”的方式

场景包含所有无序的实体。
随着系统的更新,每个系统都必须遍历所有实体并检查每个实体是否包含所有必需的组件,然后对这些实体执行更新。

显然,当有很多系统和/或很多实体时,这种方式的性能不太好。


2.使用“位掩码枚举”和映射

每个组件都包含一个位掩码形式的类型标识符(例如1u << 5/ binary [0...]100000)。然后每个实体可以组成所有组件的类型标识符(假设所有类型 ID 在实体内部都是唯一的),所以它看起来像

场景包含某种地图,系统可以在其中轻松查找合适的实体:

优点

  • 比天真的方式更快

缺点

  • 系统每次更新时都必须查找适当的实体。
  • 位掩码(枚举)被限制为位数(32 位uint32_t,至少 64 位unsigned long long),在某些情况下,您可能需要比位掩码允许的更多组件。

3. 不使用系统

Danvil下面的回答中描述了这种方法。

优点

  • 完全摆脱位掩码。
  • 可能比设计#2 更快。

缺点

  • 依赖dynamic_cast于查找组件,而设计#2 可以直接查找组件,然后安全地查找static_cast它。

4. 使用备用套件

skypjack下面的答案中描述了此方法。他非常详细地解释了他的方法,所以我建议你阅读他的答案。

0 投票
1 回答
1545 浏览

c++ - c++实体组件系统和使用模板访问组件

我一直在努力创建自己的实体组件系统,并且我准备通过执行以下操作来获取组件:

上面的函数看起来像这样:

如果找到,则返回基于关联 id 的组件,否则返回nullptr

  1. 我正在做的事情可行吗?
  2. 有没有办法确保只有从 Component 派生的类型才能用作参数GetComponent
0 投票
6 回答
7523 浏览

c++ - 在实体组件系统中将实体与系统匹配的有效方法

我正在研究一个面向数据的实体组件系统,其中组件类型和系统签名在编译时是已知的。


实体是组件的集合。可以在运行时从实体中添加/删除组件。

组件是一个小的无逻辑类。

签名是组件类型的编译时列表。如果实体包含签名所需的所有组件类型,则称该实体与签名匹配。


一个简短的代码示例将向您展示用户语法的外观以及预期用途:


我目前正在检查实体是否使用std::bitset操作匹配签名。然而,一旦签名数量和实体数量增加,性能就会迅速下降。

伪代码:

forEntitiesMatching这可行,但如果用户多次调用相同的签名,则必须再次匹配所有实体。

也可能有更好的方法在缓存友好的容器中预缓存实体。

我尝试使用某种缓存来创建编译时映射(实现为std::tuple<std::vector<EntityIndex>, std::vector<EntityIndex>, ...>),其中键是签名类型(由于 ,每个签名类型都有唯一的增量索引SignatureList),值是实体索引的向量。

我用类似的东西填充了缓存元组:

并在每个经理更新周期后清除它。

不幸的是,在我的所有测试中,它的执行速度都比上面显示的“原始”循环慢。它还会有一个更大的问题:如果调用forEntitiesMatching实际删除或添加组件到实体怎么办?缓存必须失效并为后续forEntitiesMatching调用重新计算。


有没有更快的方法将实体与签名匹配?

很多事情在编译时是已知的(组件类型列表,签名类型列表,......) -是否有任何可以在编译时生成的辅助数据结构有助于“类似位集”的匹配?

0 投票
1 回答
481 浏览

c++ - 实体组件系统混乱

现在,在开始之前,我想说我知道没有标准的方法来实现 ECS。但是,我对一种方法感兴趣,但对一件特定的事情感到困惑。

假设您有一个带有 TransformComponent(包含一个位置)和一个 RenderComponent(包含一个 Sprite)的实体,并且您还有一个与实体分开的 RenderSystem。RenderSystem 将使用 RenderComponent 处理所有组件的渲染,并且不会关心它附加到哪个实体。但是由于 Sprite 需要一个位置,所以 RenderSystem 也需要 TransformComponent。

现在是我感到困惑的部分,如果所有组件都存储在它们自己的该组件类型的向量中,我将如何获得所有同时具有 TransformComponent 和 RenderComponent 的实体?我不想使用循环遍历每个系统中的所有实体的幼稚方法,拉出同时具有这两个组件的实体,而是将每个组件都放在组件类型的向量中。此外,系统如何知道 2 个组件属于同一个实体?组件会附加一个 EntityID 吗?

编辑:我刚刚意识到,如果 RenderSystem 循环遍历所有 RenderComponents 并获取实体,然后检查该实体是否还包含 TransformComponent,那么它可以渲染它。但这有点破坏了整个“系统不关心实体”,这也要求组件有一个 EntityID,我仍然不确定它是否应该有。有人请为我澄清这一切。

0 投票
3 回答
2516 浏览

oop - 实体组件系统中的继承

我在网上阅读的大多数关于实体组件系统的材料似乎都表明它被用来避免使用继承。但是我想知道的是,在ECS旁边继续使用继承是否可行?

假设我在引擎中有特定数量的实体,它们将具有基本相同的功能。例如,能够移动的实体。那么创建一个MovableEntity添加必要组件的对象是否可行?

0 投票
1 回答
108 浏览

c++ - 实体组件系统未定义符号

我是 C++ 新手,我试图用 sfml 创建一个游戏,在这个游戏中我试图使用一个实体组件系统,我可以在这个游戏和未来的游戏中使用它,但是当我编译时我得到一个错误我不知道如何解决它。

这是我的 entity.hpp 类:

接下来是 Entity.cpp 类:

我添加组件的游戏类:

最后是我的组件及其父组件:

两者都没有在 cpp 文件中实现

这是我得到的错误:

0 投票
1 回答
3584 浏览

c# - 实体组件系统 c#

我目前正在用 C# 创建一个 2D 游戏引擎。目前,我正在实现一个实体组件系统。

我的结构如下:

  • Entity Class : 包含IGameComponent's 的列表,可以按类类型添加、删除和删除任何组件。(即;entity.RemoveComponent(typeof(Transform));。它还包含一个父实体和一个子实体列表。
  • IGameComponent 接口:目前,只是一个空接口。(注意:组件只包含数据,不包含功能)
  • 实体池:包含游戏中所有活动对象的列表,它也用于创建和销毁实体。

到目前为止一切都很棒。

但是,我面临一个问题。由于组件只包含数据,我需要一种方法来初始化、更新和渲染组件,我宁愿不只是向 GameComponent 类添加一堆虚拟方法,但我不知道有任何其他方法可以解决它。

我有哪些选择?

编辑:

我已经看到 Unity 使用像“SendMessage”这样的方法,我只能假设使用反射来调用方法。我应该实现类似的东西吗?

0 投票
1 回答
656 浏览

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

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

我的地图类由平铺地形类和一些其他数据(不重要)组成。平铺地形类以(目前)TiledTerrainLayer类的形式管理多个图层。在重构渲染系统之前,我只是继承自该类DrawableTransformable并使该类能够被渲染系统绘制。现在它需要是一个至少有 aTransformComponent和 some的实体RenderComponent

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

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

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

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

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