【发布时间】:2021-06-01 14:09:07
【问题描述】:
我正在用 Javascript(特别是 Typescript)编写一个小的实体组件系统 (ECS),它目前可以工作,但我想知道它是否可以在引擎盖下更高效。 ECS 的工作方式是实体基本上只是组件包。因此,玩家实体可能有HealthComponent、PositionComponent、SpriteComponent 等。然后您可以创建一个RenderingSystem,用PositionComponent 和SpriteComponent 查询所有实体,然后渲染它们。像这样:
for (let entity of scene.query(CT.Position, CT.Sprite) {
// draw entity
}
为了在查询时提高效率,而不是每次都遍历场景中的每个实体以查看它是否具有Position 组件和Sprite 组件,而是在第一次查询后缓存它调用然后保持更新,因此每个查询调用都可以只返回实体列表,而不是每次都首先遍历所有实体的整个列表。
因此,例如,缓存可能如下所示:
{ "6,1,20" => Map(1) }
{ "2,3,1,6" => Map(1) }
{ "2,3" => Map(31) }
{ "9" => Map(5) }
{ "2,8" => Map(5) }
{ "29,24,2" => Map(5) }
// etc..
数字是指枚举值的值,如CT.Position、CT.Sprite 等。在这种情况下,CT.Position 是 2,CT.Sprite 是 3,并且有 31 个实体具有这两个组件.因此,当查询具有这两个组件的所有实体时,我们可以只返回该实体列表,而不是每次都计算它。
这一切都有效,但效率不高,因为向场景中添加(和删除!)实体是O(n) 操作,并且还涉及大量字符串拆分和连接。您需要遍历缓存中的每个项目,以查看该条目是否包含实体的组件列表。
有什么方法可以改进它,使其更像O(log n) 或者最好是O(1)?让我知道这一切是否都清楚,或者是否有任何细节需要澄清。
【问题讨论】:
-
您能否提供一个适合放入独立 IDE 的准系统实现的minimal reproducible example,以演示其工作原理以及您需要支持哪些操作?
-
@jcalz 我可以举个例子,但我不知道如何分享。我在 Typescript Playground 网站上写了一些代码,但是 URL 太长,无法在此分享。另外,我尝试使用 URL 缩短器,但他们也说 URL 太长而无法缩短。
-
在这里,我创建了一个包含指向操场的 URL 的 pastebin(这太疯狂了..):paste.ee/p/cissL
-
您应该能够将其编辑到您的问题中,而不仅仅是将其放入 cmets,我想。如果您计划频繁添加/删除实体,我不确定缓存特定查询是否有意义;我想这真的取决于使用模式。如果您不经常添加/删除实体,那么在发生这种情况时丢弃缓存可能是合理的,而不是尝试逐行修复缓存。在任何情况下,我都不愿意在不分析典型用法的情况下对性能做出任何强烈的主张。 ??????
-
有趣的 sn-p 我得再读一遍。是的,我最近意识到我的问题基本上是“我如何快速找到 N 个集合之间的交集?”所以我在谷歌上搜索。显然布隆过滤器可能在这里工作?我现在正在阅读它.. 不确定我是否理解正确,但看起来您可以在 N 个布隆过滤器上进行设置交集以找到匹配的项目。 stackoverflow.com/a/39176090/962155
标签: javascript typescript algorithm data-structures hashmap