问题标签 [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 回答
63 浏览

c++ - 通过组合不同的类型创建唯一的 id

我想通过“组合”类型来创建一个唯一的 id。输入类型的顺序无关紧要,输入相同的类型组合应始终返回相同的 id(在相同的运行时)。我想在实体组件系统中使用它来识别组件的组合。

一个几乎可以完成工作的想法:

Output: 1, 1, 2, 2 Goal: 1, 1, 1, 1

这将返回一个唯一的 id,但它确实关心订单。也许这可以通过某种CreateArchetype()“可变模板排序魔法”以某种方式对函数中的类型进行排序来解决,但我还没有设法做到这一点,有可能还是有其他选择?

0 投票
0 回答
112 浏览

swift - 如何将 ECS 与 SwiftUI 结合使用?(实体组件系统)

也许你可以照亮我黑暗无知的道路?我的目标是一个 SwiftUI 应用程序,我可以在其中将组件注入视图并让系统在这些组件上运行一些逻辑。每次我觉得我已经到了;基础的弱点让我重回起点。让我告诉你我试过什么!

这是基本的数据组件。我将EntitasKit用于我的实体组件系统。

这是应用程序范围的 EntityService,它包含实体及其组件的上下文。它是使用Resolver注入的。

现在,这是 SwiftUI 中的视图。

EntityState 就是它听起来的样子;一个属性包装器,它捕获实体组件的状态并使其对 SwiftUI 可见。

SwiftUI 会注意到动态属性中的状态变化。单击该按钮将重新呈现视图并更新实体上的组件。

当我添加一个更改组件的系统时,这个基础开始崩溃。

问题是 SwiftUI 状态永远不会被通知,但我希望 SwiftUI 知道组件在系统更新时发生的变化。

我尝试了许多不同的方法:

  • 使用@Published 将组件/实体/上下文作为 ObservableObject。我的理解是,这是将数据模型连接到 SwiftUI 的好方法。我有@Published 组件、组件和实体中的数据,但一直阻止我的问题是让 EntityState 重新渲染视图。由于上下文被注入,我不能使用其他属性包装器,如@ObservedObject。
  • 绑定。我尝试观察 EntityState 中的组件对象并将组件绑定传递给实体,但我无法将绑定存储到同一个字典中的不同 DataComponents。我什至不确定对绑定的更改是否会返回到 EntityState 以重新呈现视图。同样的限制也适用于@States 的绑定。无论如何,我已经把自己困在这条路上了。
  • 发布者和订阅者。将 EntityState 转换为订阅者以便它可以接收值需要它是可变的。要使 EntityState 可变,它必须成为一个类,但这会破坏 SwiftUI 重新渲染。发布者可以是某种主题或组件的自定义发布者。我只是无法解决如何接收值并将它们分配给状态,因此 SwiftUI 重新呈现。整个联合区域对我来说有点模糊。可能有一种聪明的方法可以做一些我不知道的惊人的事情。

如何从系统将组件分配给状态,以便 SwiftUI 重新渲染?

我希望你发现这是一个有趣的问题来解决,它让你和我一样对解决方案感到好奇。至少让我很兴奋。

祝大家拥有美好的一天!

0 投票
1 回答
153 浏览

java - java中的ecs:如何享受缓存友好?

ECS(entity component system)之所以像entitas in unity一样具有出色的性能,是因为相同类型的组件被放在同一个内存块中,这使得组件迭代快速高效。

然而,在java中我们无法管理对象内存位置,所以ecs似乎不如java语言中的c++有用。这是真的吗,或者实际上有一些方法可以在 java中实现缓存友好的 ecs ?

0 投票
1 回答
392 浏览

c++ - 我的游戏引擎的 Entity-Component-System 中的 GetComponent<>() 函数返回编译器错误 C2440

此问题与在 Windows 10 操作系统中运行的 C++ 应用程序中的 Visual Studio 2019 中的编译器错误有关。这可能是一个中级或更高级别的问题。

概括

我有这个功能:

此函数导致编译器错误 C2440:

'return':无法使用 [_Ty=Component*] 和 [T=Name] 从 '_Ty' 转换为 'T*'

此错误还附加了以下两条消息:

消息:从基础转换为派生需要 dynamic_cast 或 static_cast

消息:请参阅使用 [T=Name] 编译的函数模板实例化 'T *Scene::GetComponent(EntityID)' 的参考

此错误出现 3 次,每次 T 等于 Name、Transform 和 Sprite(到目前为止,我的游戏引擎中的每个组件)

MSDN 上的编译器错误 C2440:https ://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/compiler-error-c2440?view=vs-2019

功能说明

ECS设计

我的实体组件系统通过两个数组存储实体和组件。

第一个是componentIndexes,用于将实体索引到第二个数组中,第二个数组components将根据索引返回一个组件。本质上,如果您听说过使用“稀疏”数组和“密集”数组来压缩数组,那componentIndexes是我的稀疏数组,components也是用于在场景中存储组件的密集数组。

简而言之:

componentIndexes存储 CompIndex 类型组件的索引,前提是:[ComponentType][entityID] | 参见图 1A

components存储 Component* 类型的组件数据,提供:[ComponentType][index] | 参见图 1B

Graphic 1A | componentIndexes

Graphic 1B | components

逐行

此函数按预期工作,并返回一个枚举 CompTypeID,用作组件类型的数字表示。这可用于根据我要定位的组件类型对我的componentIndexes和数组进行索引。components

此函数按预期工作,并返回一个布尔值,无论实体是否具有特定组件。如果提供的类型 T 不是组件或实体没有该组件,它将返回 false。Else return nullptr 是此函数的不言自明的失败状态。

这些函数获取并返回类型为 的组件Component*ECS 设计中解释了这是如何做到的。中的每个元素都components应该存储组件 - 这些是结构,并且从空结构Component(例如struct Name : Component {};)继承。因为它们是从父类 Component 继承的,所以我应该能够将每个子“组件”存储在其中,components因为它存储了Component*.

我认为问题是什么

T 的类型GetComponent<T>(EntityID)将等于 Name、Transform 或 Sprite。的存储类型componentsComponent*. 虽然 Name*s, Transform*s, & Sprite*s 都可以存储在 中Component*,但编译器似乎不允许我将类型Component*数据分配给类型数据Name*(或其他组件) - 所以理论上我应该能够获取名称我的数组中Component*的数据,我无法这样做,因为我无法将它从 GetComponent 函数作为Name*.

我担心这个问题可能是由于对如何将孩子存储在一系列父母中的工作方式的根本误解引起的——也许这只存储了孩子的父母部分?

我只能想象这是通过两种方式之一解决的。

  1. 考虑到父指针的位置,我可能有一种方法可以获取子节点的信息——如果父子指针彼此相邻,可能会根据父子指针的大小偏移内存中的指针?我不认为 C++ 会以这种方式公开内存引用,也许这种方法只能使用 Assembly,因为指针信息隐藏在类型名(如int*or Component*)后面。
  2. 另一种方法可能是使用智能指针或(如附加到错误的消息所述)显式动态转换或静态转换的一些魔术;但我不知道这三样东西是如何工作的,它们是做什么的,如何使用它们,或者什么时候应该使用它们。

这些是我最好的猜测——它们真的是我在黑暗中拍摄的。如果您有更好的想法,请分享它,我会尽力研究它。这是一个编译器错误,我在 Google 搜索中几乎找不到文档或谈论它,所以我认为对此做出贡献是合适的。

免责声明

有时我发现由于结构化的课程课程,我错过了大多数人早早掌握的一些基本信息。我猜这是我将学习智能指针和动态指针的地方。

资源

场景.h

场景.cpp

实体.h

组件.h

名称.h

组件.h

0 投票
1 回答
348 浏览

entity-component-system - 如何在 ECS 游戏中处理重复数据,以及有关 ECS 的更多一般问题

我正在阅读关于 ECS 的文章,这些文章显然非常适合开发游戏。

我遇到了一个问题,或者一个问题,我会举例说明这个(这正是我遇到的问题)。

我有多个组件Boss, Minion, Player, Weapon, Name. 首先,我namePlayer组件中添加了一个字段。但是由于这些组件中的每一个都可以命名,所以我很想将它模块化并创建一个Name组件。大多数系统不会以相同的方式使用该名称,但有些会,主要是DebugSystem.

事实上具有组件的实体Player不能具有Name组件,但应该。我怎样才能轻松处理这个?

那是 :

  • 我只能用组件创建一个实体Name
  • 当我使用组件创建实体时,Player组件Name已经存在或应该自动创建。如果可能,直接在另一个组件中获取名称,例如entity.GetComponent<Player>().name.

理想情况下,该名称可以在具有名称的任何组件之间共享。它让我想起了 OOP 中的钻石问题,但 ECS 不是部分创建来解决这个问题的吗?

问题 1) ECS 中是否有标准方法来处理这个问题,或者应该由最后CreateEntity()添加缺失组件的函数手动处理?

关于 ECS 的其他一般问题:

我从继承Entity类开始,做生产链,如果我正确理解了原理(类本身并不重要,但它会自动创建组件)。然后我创建了其他一些实体类,但最终它们实际上可能只是组件。最后我什至不知道 Entity 类是否应该是可继承的。

问题 2)实体类在 ECS 系统中是否从未被继承?

在很多介绍文章中,他们并没有谈到组件之间的交互,但是在q/a论坛中,他们通常会提出一个事件驱动的系统来解决问题。

问题 3)事实上,ECS 模式是否与消息系统模式不可分离,应该一起使用(至少在大多数情况下),或者是否有纯粹使用 ECS 模式的解决方案?一些答案说事件完全破坏了 ECS 的优势,另一些人则建议这样做。

问题 4)组件可以包含指向其他组件的指针吗?组件可以包含指向其他实体的指针吗?我知道大多数答案都说它只是一个工具,没有什么不好的,但我想保留 ECS 的优势,而不违背它的原则。

问题 5)系统可以有任何数据吗?我没有找到任何关于它的东西。我正在考虑一个基于回合的游戏,我必须在其中存储回合数。因为数据不是一个具体的组件(它是系统本身的一些数据),所以我很想 1)GameData在一些像全局游戏状态一样的实体中创建一个单例组件 2)将数据放入TurnSystem,假设一次只能玩一个游戏。

0 投票
1 回答
216 浏览

rust - 如何在 Rust SPECS 中读取组件并写入具有相同组件的新实体?

我有一个正在生成其他实体的实体。例如生成器有一个位置组件,我希望生成的实体与生成器具有相同的位置。

在生成系统中,似乎我需要读取和写入一个组件,这听起来不可能。唯一的选择似乎是 a LazyUpdate,但我想避免这种情况,因为它需要调用world::maintain,并且我想在同一框架内的另一个系统中使用生成的实体。

我的系统代码:

我该如何解决这个问题?

0 投票
2 回答
160 浏览

rust - Rust - 在 Vec 中获取组件> (ECS)

我是一名使用 Rust 语言的初级开发人员。我来自 JavaScript,很多特性和特性对我来说仍然不清楚。

目前,我正在寻找在 Rust 中构建自己的 ECS(实体组件系统)系统。当我想从实体中获取组件时,我一直卡住。

实际上,我使用 dyn 盒装矢量将组件存储在实体中,这是一个好方法吗?

我的代码:

如何从我的实体中取回我的 Position 组件?

编辑:

这里,一个获取组件的测试函数(在实体实现中):

谢谢。

0 投票
0 回答
47 浏览

kotlin - 在 Kotlin 中使用委托实现时传递此引用

我正在使用委托实现来创建一种实体组件系统。

一个简化的例子:

编译器给了我一个在:this的构造函数中使用的错误。这个问题的答案说,由于 JVM 相关的限制,在对象构造的这个阶段使用指针是不可能的。PlainElectricComponent'this' is not defined in this contextthis

我知道我可以component稍后进行初始化,例如通过

但这会强制构造一个丑陋的构造函数,并且需要额外的“接线”,这很容易被遗忘。

您是否知道另一种方法可以让实体的组件声明保持直截了当?

PS:Oven实现接口后,我可以充分使用编译器类型检查、智能转换等。

0 投票
1 回答
423 浏览

rust - 是否可以在不直接将 World 与线程本地系统一起使用的情况下向实体添加一个或多个子级?

我有一个Entity和一个BundleComponents想附加到一个将成为第一个实体的子实体的实体。我可以用Commands我的组件生成一个实体,但我无法得到它的实际Entity值,这意味着我不能直接构造Children组件。如果我使用该World资源并使我的系统线程本地化,我可以在Entity生成它时获取我的子实体,然后使用它来制作Child组件,并将其添加到第一个实体。我无法让线程本地系统正常工作,而且对于应该是一个简单而常见的操作来说,它们似乎太过分了。

有什么方法可以使用常规系统将子实体添加到另一个实体?

澄清一下,这就是我的理想语法:

0 投票
2 回答
209 浏览

c# - C# 中实体组件系统的多态性

我目前正在开发一个实体组件系统变体,其中实体知道他们的组件。通常你访问这样的组件:

这样做的问题是,我希望某些对象始终具有某些组件并以类型和 null 安全的方式访问它们。而不是这样做:

我宁愿使用:

我能想到的唯一方法是使用接口并实现如下:

这显然有一些缺点。如果有人删除了这个组件怎么办?如果添加第二个呢?

你能想出一种更聪明的方式或模式来实现我想要做的事情吗?而不是通过组合而不是通过继承?

感谢您阅读:)