问题标签 [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 投票
2 回答
172 浏览

c++ - 四嵌套 unordered_map 怪物的替代方案?

我一直在尝试寻找一种有效的方法来存储和检索许多对象。让我解释一下我想要实现的目标,然后列出我想出的选项(但我不满意)。

以下在技术上做了我需要它做的事情,但显然是一个禁忌:

最内部的地图根据其 ID 保存组件。它之前的每个类型都有一个映射(组件的子类)。后者是这样完成的,以便当我检索它们时,我可以完全安全地动态地将它们转换为它们的类型,因为知道 TYPE 哈希映射只包含它们的类型的指针,还允许使用 count 来快速检查某个 ID 是否存在某些东西. 后面的地图按层存储,第一个地图按场景存储。在任何时候,将举行大约 30-50 个场景,每个场景包含大约 6-10 个图层,每个图层包含大约 30-40 个类型,每个类型包含 1 到 500 个对象。

每个循环我们都会根据指针的类型迭代指针,一次一层。场景很少改变(每 2-3 分钟)。使用 Type 和 Id 的组合访问组件。代码会定期检查哪些其他组件类型存在于同一 Id 中。场景、层和类型可以通过它们的名称进行访问,名称存储为 32 位 CRC 散列。速度至关重要。ID 是由代码分配的数字,只是从 0 开始。ID 在每个场景中都是唯一的。

毫无疑问,有一些疯狂的(阅读:常见的)成语可以帮助我,而我从未听说过。有谁知道吗? 到目前为止,我提出的任何替代方案都不可接受,但无论如何我都会列出它们:

选项1:

组件保存它来自哪个类型、场景和图层,每当我们遍历所有条目时,我们都会忽略不来自当前场景或图层的条目。或者,按顺序存储它们,以便您只需在一定范围内进行迭代。向量包含组件,当我们需要访问某种类型的组件时,我们会通过向量进行搜索。不理想,因为它需要一个周期进行多次搜索。或者使用 unordered_map 代替向量。

选项 2:

与嵌套地图相同,但带有向量。映射将 Id 转换为向量内的索引。

选项 3:

(Type / Layer / Scene / Id) -> Component* 简单地用向量的索引存储所有组件。有一个 unordered_map,其中包含主存储向量中的索引向量。当我们检查两者之间的冲突时,ID 和字符串哈希都可以存在(不太可能)。对于场景、图层和类型,名称必须是唯一的。ID 返回该 ID 的组成部分的所有索引的向量,名称或类型返回包含该类型或场景的所有索引的向量。感觉 hackish,所有这些向量的迭代。

选项 4:

组件获取一个“Component* next”指针来遍历属于同一实体的组件。最后一个组件链接到第一个。组件再次获得类型和场景/图层成员。

0 投票
2 回答
3021 浏览

c++ - 如何从接口获取派生类?

在尝试用 C++ 创建实体组件系统时,由于缺乏对语言的了解,我遇到了一些问题。

使用一个类Entity,它包含接口IComponent(它的作用更像是一个表示“我持有数据”的标志),我有一个方法Add,如果没有同一个类的另一个 IComponent 已经在它。

这是一个过于简化的示例代码:

我的预期结果是

但我不知道如何从 IComponents 列表中获取 Foo 和 Bar 的基类并检查它们是否重复。

我怎样才能得到它们?如果 Foo 在 IComponent 列表中,我如何将 IComponent 转换为 Foo?

0 投票
1 回答
647 浏览

c++ - Entity-Component-System 中的拆分组件需要过多的重构

我有一个使用实体组件系统 (ECS) 的现有 C++ 游戏库。

我的图书馆的用户想创建一些组件,例如Cat:-

他可以修改hp每一个cat,例如:-

几天后,他想Cat分手HPFlyable-

因此,每次cat访问hp都会编译错误(例如,#1在上面的代码中)。

为了解决这个问题,用户可以将他的代码重构为:-

它可以工作,但需要在用户代码中进行大量重构(调用 的各个地方cat->hp)。

在 ECS 中拆分组件时如何编辑框架/引擎以解决可维护性问题?

我从未发现任何不受此问题影响的方法,例如:-

赏金原因

Yuri 的回答是一个很酷的技术,但它仍然需要一些重构。

我当前糟糕的解决方案(pimpl)

如果我想创建Cat,我将创建 6 个组件:-

  • Hp_,Hp_OO
  • Flyable_,Flyable_OO
  • Cat_,Cat_OO

这是一个代码示例:-

现在,调用是有效的:-

实施:-

  1. 如果用户添加Cat_OO到实体,我的游戏引擎会自动将其父类添加到实体,例如Hp_Hp_OOFlyable_Flyable_OOCat_
  2. pimpl 的正确指针/句柄也必须分配。

  3. ^ 两个动作都可以使用回调。

缺点是:-

  • 需要创建很多组件。(浪费记忆)
  • 如果有一个通用的基类,例如BaseComponent,我需要虚拟继承。(浪费大量内存)

优点是:-

  • 如果用户查询getAll<Hp_OO>(), Hp_OOof eachCat_OO也将在返回的列表中。
  • 无需重构。
0 投票
0 回答
61 浏览

unity3d - 如何实施“可见性系统”

我已经设法在不在屏幕上的实体上禁用动画。但是,我正在寻找一种更纯粹的基于数学的方法(而不是视口点技巧)。有人知道我怎样才能有效地“Jobify”这段代码吗?

0 投票
1 回答
1710 浏览

data-structures - 如何处理 ECS 中的动态分层实体

这是一个类比:我有一个由细胞组成的有机体,这些细胞可以进一步由一系列附件组成。

我目前拥有的是一种子/父母之间的事件链来处理附加和分离组件(这可能会影响链上的任何东西),它根本不涉及 ecs,它们是实体中的函数。

现在我已经使用了事件组件(用于对象上的鼠标事件)。如果我希望系统是纯的,我会在附加组件等时创建附加组件吗?即便如此,我如何才能让所有必要的接收者进入使用该组件的系统?以这种方式而不是一系列功能来处理它是否值得?有没有更好的办法?

0 投票
0 回答
3680 浏览

c# - 具有本机集合的 Unity 作业系统比具有 C# 集合的作业系统慢

我目前正在研究一个 CPU 非常繁重的模拟,并且已经转移到作业系统 + 突发编译,并且可以大大提高性能。也就是说,切换到工作系统创造了一个新的瓶颈。我想问是否有任何方法可以规避这种情况。

这是我的模拟的工作原理。它基本上在世界空间中移动一个 2d 矩形并捕获路径上的网格坐标。没有工作,最大的瓶颈是SampleLine,有了工作系统,瓶颈是trajectory.Add/.AddNativeoccupied.IndexOf

trajectory.Add使用 a Dictionary<int2, float2>,而 .AddNative 使用 aNativeHashMap<int2, float2>来存储值。trajectory.Add几乎是 AddNative 的两倍,即使我必须先将 NativeList 的所有值复制到一个无用的 List 中。通过使用 Array 作为缓冲区,我可能会使其更快。

这是使用的工作:

现在我的问题是,如何防止代价高昂的NativeListvsList转换?为什么将 a 添加NativeList到 aNativeHashMap比将 a 转换NativeList为 aList并将该列表添加到 a 慢Dictionary

另外,将工作分成更小的工作可能会更好,因为我可以调用SampleLine甚至WorldToCell并行调用?但是我不知道工作是否可以开始其他工作,或者我是否应该只做WorldToCell一份工作(因为它被称为最多)并在普通 C# 中完成其余的工作?我对工作系统完全陌生,所以我不知道应该如何“工作”。我可以把它留在一个大工作中,我可以做很多小工作,WorldToCell或者我可以把所有三个计算都做一个工作。

0 投票
0 回答
380 浏览

unity3d - Unity3D 即将推出的 ECS 与当前层次结构

介绍

我一直在关注 Unity3D 的 DOTS 开发,并且一直在做一些关于让 ECS 运行的教程。但是,我没有发现 Unity3D 正在弃用他们当前的 GameObject/Hierarchy 方法并用新的 Entity/ECS 方法取而代之这一点很明显。

理论

目前,它似乎是两者的混合体,因此通常属于对象池或可能导致内存碎片的任何东西(射弹、物品、重生单位等)都使用 Entity/ECS,其余的仍然使用 GameObject/Hierarchy .

这对我来说似乎不太理想,因为非最佳方法将阻止进入最佳方法等待的下一帧。如果只使用 ECS,你会得到更多的帧,这有点意思......

另一方面,必须让设计师和动画师使用 ECS 之类的东西会很昂贵(目前)并且技术含量更高。编辑器中的当前 ECS 窗口并不是很直观,它不是一个工具,而不仅仅是一个结果输出。

问题

所以我的问题是,Unity3D 是否计划保留混合方法,如果是,我们如何选择是使用实体还是游戏对象?或者如果他们只使用 ECS 方法,是否会更改当前的实体编辑器窗口以适应设计师/动画师?

0 投票
1 回答
91 浏览

java - Java - 铸造 Set 的缺点?

我正在用 Java 开发一个基本的基于实体组件系统的游戏引擎,以获得乐趣。

我需要一种快速的方法来获取Component某种类型的所有 s。例子:

所以我有一个ComponentManager应该处理这个的:

我的 IDE 不喜欢(Set<T>) active.get(compClass);(以黄色突出显示)。然而,这是基于非常基本的测试,并且比单独铸造每个项目Set并将它们添加到新的更快Set,但是这样做的潜在缺点是什么?

0 投票
1 回答
303 浏览

java - 在 Java 中存储 ECS 的组件

我正在使用 ECS(实体组件系统)在 java 中创建一个网络游戏,这是我第一次使用 ECS。我不确定我应该如何存储组件。我确实想使用一个实体类,我将在其中存储该特定实体的组件,但是如何?我是否应该从基类扩展所有组件并将它们存储在数组列表中?我应该使用集合吗?我基本上只是问是否有人对如何做到这一点有任何建议?谢谢。

0 投票
1 回答
1025 浏览

c++ - 在 C++ 中将系统与 ECS(实体组件系统)管理器分离

我目前正在制作一个实体-组件-系统程序作为学习 C++ 的一种方式(我知道这可能不是推荐的方式,但我很开心)。到目前为止进展顺利,但我希望对其进行更多改进。

当前,每个系统都添加到 ECS 管理器中,std::function并附有它需要运行的组件的签名。我当前的策略是遍历每个系统和实体,如果组件签名匹配,则使用实体 ID 作为参数调用系统函数。

此函数通过以下方法附加到 Manager:

ComponentA并且ComponentB只是泛型类型。我什至可以让一个组件成为一个float或者int如果我需要的话。使用时getComponent<T>(),这些被转换为适当的指针。

这一切都完美无缺,但最终发生的是我必须为每个系统包含管理器的头文件,我希望它们不要相互绑定(我想这将是关注点分离)。

最好每个过程最终看起来都类似于:

系统唯一需要知道的是它正在处理的特定实体的组件指针。

我目前std::unordered_map根据其类型的位掩码将组件存储在一个中。当需要一个组件时,模板提供了我能够从中制作位掩码然后转换它的类型。我不确定是否可以存储要转换的组件的类型,所以我认为每个组件都必须作为 void 指针传递给函数。但是 C++ 不允许我在void*不知道类型的情况下从 a 隐式转换为另一个指针。有没有办法可以存储每个组件的类型以便以后需要时进行转换?

我想我可能只void*为系统所需的每个组件定义函数,但直观地说这似乎是个坏主意。它根本不是类型安全的,我无法通过查看函数声明来知道它需要什么参数。

如何将引用传递给可以采用任意数量的任何类型的指针的函数?有没有办法通过模板来做到这一点,或者我可以在不知道类型的情况下隐式转换一个 void 指针?我也对其他策略持开放态度。