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

c++ - 关于纯 ECS(实体组件系统)和更新系统的问题

我已经写了一个 ECS,但我对更新阶段有一些疑问。(在系统中)我读过很多文章,但没有找到对这类问题的引用。

为了从 ECS 中受益(例如缓存友好),它们是以下要求:

  • 实体必须只是一个 ID。
  • 组件必须是纯数据(没有逻辑的结构)。
  • 系统包含逻辑并更新组件。
  • 系统之间没有交互(而是系统通过向实体添加“标签”组件进行通信)。

因此,每个系统中应用的逻辑都很好,并且在它们不是“用户代码”时都可以正常工作。但是,当我们处理用户代码时(例如,用户可以将 C++ 代码附加到对象(如 Unity、Unreal)),问题就来了:

  1. 由于组件只包含数据,当用户修改本地位置时,世界位置不会更新(世界位置将在Transform System处理每个Transform Component时计算。所以如果用户在修改后询问世界位置它的本地位置,它将获得以前的世界位置,而不是实际位置。
  2. 当一个实体被移除时,它的孩子必须被移除。由于组件仅包含数据而不包含逻辑,因此不会删除子组件(它将在下一次父系统更新中)。所以我们有一些“延迟”(孩子仍然可以访问,但将在下一次父系统更新时被删除)。
  3. 假设我们有实体 A、B、C。B 是 A 的子代。在用户代码(实体附加的 c++ 代码)中,用户设置 B 的父代有 C,然后删除实体 A。当父系统将更新,它会检测到 A 已被移除,(它也可以检测到实体 A 的父级已更改)但是系统如何知道实体 A 是否在实体 B 的父级更改之后或之前已被删除?

在组件中添加逻辑将破坏纯 ECS 的优势(以缓存友好的方式对所有相同的组件执行相同的操作),所以恕我直言,这不是一个解决方案。

有人有解决方案吗?我想知道您如何处理 ECS 实施中的此类问题。

谢谢!

0 投票
2 回答
115 浏览

c++ - Why is it possible to modify a static const variable that is declared inside a function?

I'm implementing an ECS framework for my game engine and investigating ways to identify component types at runtime. This means I can dynamically group components of a similar type contiguously in memory. For example, I can have two separate arrays for Position and Velocity components that my systems can loop over.

I currently use typeid(), but I came across an article that uses static const variables to generate unique IDs for each type. The general idea can be summarized in the code snippet below:

This outputs 1 1 3, but I would expect that since it's attempting to modify a constant (specifically at the second call), it would fail to compile. Why does this work?

0 投票
1 回答
464 浏览

c++ - C++ 如何使用子类制作 unordered_map

我正在制作一个游戏引擎,目前我正在研究实体组件系统。这里有一些代码可以更好地理解:

还有一个简单的父类EntityComponent,它只处理 ID(我跳过了一些代码,因为它在这个问题中并不重要):

而且是孩子。其中之一是TransformComponent

所以问题是我想创建一个实体,向它添加一个 TransformComponent 并使用它的函数 GetPosition()、GetScale()。

创建实体并添加 TransformComponent 是可行的,但是当我想使用 GetComponent(id) 时,它会返回父类EntityComponent,因此这意味着我不能使用 GetPosition() 等函数。

如何更改代码,以便将EntityComponent的不同子级添加到 unordered_map 并使用它们的 ID 接收它们并使用它们的公共方法?

0 投票
2 回答
1076 浏览

c# - 实体框架核心 - 异步/同步 - DbContext

我来给你一些建议。我正在开发一个需要外部库的控制台应用程序(服务器)。

我使用实体框架核心。但是我对 async / await 的概念仍然存在差距。我已经阅读了很多东西,尝试了很多东西。

我建立了一个关于数据库和 ECS(实体组件系统)架构的实体/DAL/BLL 架构。

我有调用事件(OnInitialized)的系统。在这种情况下,我需要从数据库加载不同的数据(取决于系统)。

在同一个 DbContext 上同时进行多个并行查询是不可能的。我只有一个包含多个表的数据库。

那么我应该开发与数据库完全同步的交互吗?

或者是否有同时使用多个异步的模式?

0 投票
1 回答
378 浏览

c++ - 如何在 ECS 模型中组织实体?

我有一个渲染系统,它遍历所有 MeshDrawData 组件并批量绘制它们。我的 ECS 实现只允许每个实体使用一种类型的组件。

现在我想代表“玩家”乒乓球拍。我的 OOP 心态是这样说的:

这行得通,但是假设现在我也想渲染一条线。如果我这样做:

在这里你可以看到问题.. 我为实体 e. 创建了两个 MeshDrawData 组件。

鉴于我的虚幻引擎背景,我创建了一个演员并向其添加组件。我一直认为在 ECS 中,实体类似于演员,但我发现我完全错了。

例如,您如何组织您的实体以允许使用我之前提到的用例?一个实体应该代表什么?

可能的解决方案:

  1. 永远不要使用在同一实体中创建相同 MeshDrawData 的 SpriteComponent 和 LineComponent 创建实体..(明显但容易出错)
  2. 为每个 SpriteComponent 和/或 LineComponent 创建一个子实体,并将它们添加到各自的子实体。这会起作用,但它会使实体层次结构树变长..不确定它是否更容易出错。...
0 投票
1 回答
398 浏览

rust - Rust 中的动态类型实体组件系统

问题

我正在为我正在尝试构建的游戏引擎构建一个实体组件系统,但我不太确定如何使用严格类型的语言(在本例中为 Rust)进行操作。

我希望组件类型是任意结构,可以包含有关实体的任何类型的状态,但不知道行为。这样,例如,实体可以包含PositionHitboxVelocity组件,但物理子系统可以单独更改或交换,而无需修改有关这些组件的任何内容。

我还想让从模块外部添加新的组件类型成为可能。这将允许新游戏模组将其自己的自定义组件添加到现有实体,而无需修改游戏的核心代码。

我对 Rust 还很陌生,并且在 C++ 方面做了有限的工作,所以我可能完全采用了错误的方法,如果是这样,我会很感激关于解决这个问题的更好方法的建议。

在没有严格类型系统(而且我更熟悉)的语言中,比如 JavaScript,我可以拥有一个包含任意类型组件集合的实体数组,然后进行运行时类型检查以获取数据:

在上面的示例中,实体可以包含任何类型的组件,处理它们的系统可以检索它们所依赖的特定组件,直接访问它们的具体属性,然后修改组件。外部代码还可以向其中一个实体添加一个完全未知的组件,并且不需要更改物理组件来适应它。这与我希望在我的 rust ECS 中具有的行为相同。

作为旁注,由于游戏需要比我的示例 javascript 提供的更高性能的解决方案,我想尽量减少指针间接、哈希表查找、内存分配和优化数据局部性,但自然优化仅次于功能。我的示例代码忽略了这些优化。

我一直在尝试的

我考虑过创建一个 的 hashmap ComponentStorage<T>,其中ComponentStorage的 trait 允许我抽象用于存储组件的底层数据结构。一个State结构将包含一个HashMap<ComponentStorage<std::any::TypeId, T>>. 可以通过 TypeId 哈希查找特定存储,然后使用 ComponentStorage 特征,我可以Option<T>通过实体 ID 从该存储中检索 a,然后访问T包含的任何属性。

但是,这不起作用,因为 T 中的每个项目的类型都不同HashMap,并且我无法通过创建单个特征来为类型参数的每个变体实现来擦除类型参数(如在类似问题中所建议的那样:Rust 中的通用结构向量),因为我需要访问处理实体的系统中的具体类型 T。

我可能会通过使用来存储组件来实现类似于我的示例 JavaScript 的东西Any,但我的理解是,Any在任意自定义结构上使用意味着没有相邻存储,并且指针间接丰富。我并不是要过早地进行优化,但我很犹豫是否沿着这条路线进行原型设计,因为如果Any以后不完全重写它,似乎无法克服这些限制。

由于显然必须发生指针间接以便不将类型硬编码到该系统中,我希望组件的集合,而不是组件本身,是多态的,同时能够访问包含在给定集合的具体类型。

您可以在这里为我提供任何帮助,我将永远感激不尽。谢谢!

0 投票
0 回答
755 浏览

unity3d - IOS 上的 Unity ECS/Burst

我在 macOS Mojave.10.14.6 下使用 Unity 2019.3.0f6 创建了一个新项目

向场景中添加了一个简单的立方体,并包含来自包管理器的以下包:

  • 实体预览.11 - 0.5.1
  • 爆发 1.2.2

我可以在 Unity 上将项目构建为 Release,并且在 xCode(v11.3.1) 上成功构建。

但是当我尝试在带有 IOS 13.3.1 的 iPhone X 设备上运行它时,我得到了以下异常:

NotSupportedException:要编组托管方法,请将名为“MonoPInvokeCallback”的属性添加到方法定义中。我们尝试编组的方法是:Unity.Burst.BurstCompiler.Compile[T] (T delegateObj, System.Boolean isFunctionPointer) [0x00000] in Unity.Entities.StructuralChange::AddComponentEntitiesBatchExecute (T delegateObj, System.Boolean isFunctionPointer) [0x00000] in <000000000000000000000000000000000>:0 在 Unity。 Entities.StructuralChange.Initialize () [0x00000] in <000000000000000000000000000000000>:0 在 Unity.Entities.EntityManager..ctor (Unity.Entities.World 世界) [0x00000] in <000000000000000000000000000000000. ctor (System.String name) [0x00000] in <00000000000000000000000000000000>:0 在 Unity.Entities.DefaultWorldInitialization.Initialize (System.String defaultWorldName, System.

(文件名:目前在 il2cpp 线路上不可用:-1)

知道为什么在一个简单的项目中会发生这种情况吗?

0 投票
1 回答
441 浏览

unity3d - Time.timeScale 不适用于 Unity.Physics 包(DOTS)

如果我设置 Time.timeScale = 0; 如果设置 Time.fixedDeltaTime = 0,则没有任何变化;我的物理对象开始出现奇怪的行为,但并没有完全停止。也许有人知道如何更改 DOTS Physics 的 timeScale

0 投票
1 回答
35 浏览

c# - 在围绕目标运行时控制船舶旋转

我试图让我的飞船实体要么看向他们正在移动的方向,要么看向他们正在绕行的目标。在这一点上,我会对任何一个结果感到满意。不幸的是,尽管我对如何实现这一点进行了所有谷歌研究,但我似乎对底层数学的理解还不够。

这是我目前在我的 RotateSystem 中拥有的

这样做的结果是,船只有 1/2 的时间面向其轨道目标,而另一半的时间则背对着轨道目标。 在此处输入图像描述

0 投票
0 回答
133 浏览

paradigms - ECS系统实现,为什么迭代注册实体而不是连续组件数组

我读过的很多关于 ecs 系统实现的文档似乎都有一个动态数组,用于注册系统想要与之交互的实体。

确实,它允许您轻松地拥有多个组件宽度的实体,但不要违背让组件管理器将您的组件保存在一个连续数组中的整个目的,以避免处理器必须转到每个内存的另一个区域迭代?

因为现在如果我们对动态数组的每个实体进行迭代,即使系统只寻找宽度为一个组件的实体,处理器仍然需要在每个实体、他的组件和下一次迭代之间来回做。不谈关注多个组件的系统

或者也许处理器很聪明并且会注意到我们所做的并优化它?