问题
我正在为我正在尝试构建的游戏引擎构建一个实体组件系统,但我不太确定如何使用严格类型的语言(在本例中为 Rust)进行操作。
我希望组件类型是任意结构,可以包含有关实体的任何类型的状态,但不知道行为。这样,例如,一个实体可以包含 Position
, Hitbox
, 和 Velocity
组件,但物理子系统可以单独更改或更换,而无需修改有关这些组件的任何内容。
我还想让从模块外部添加新的组件类型成为可能。这将允许新游戏模组将其自己的自定义组件添加到现有实体,而无需修改游戏的核心代码。
我对 Rust 还很陌生,并且在 C++ 方面做了有限的工作,所以我可能完全采用了错误的方法,如果是这样,我会很感激关于解决这个问题的更好方法的建议。
在没有严格类型系统(而且我更熟悉)的语言中,比如 JavaScript,我可以拥有一个包含任意类型组件集合的实体数组,然后进行运行时类型检查以获取数据:
class Position {
constructor(x = 0, y = 0, z = 0) {
this.x = x;
this.y = y;
this.z = z;
}
}
class Velocity {
constructor(x = 0, y = 0, z = 0) {
this.x = x;
this.y = y;
this.z = z;
}
}
const world = [
[
Position(0, 0, 0),
Velocity(0.25, 0.1, 1.2)
]
]
const physicsSystem = (world = []) => world.map((entity = []) => {
const velocity = entity.find((component) => component instanceof Velocity)
return velocity != null ? entity.map((component) => component instanceof Position
? Position(component.x + velocity.x, component.y + velocity.y, component.z + velocity.z)
: component
) : component
})
window.setInterval(() => world = physicsSystem(world), 100)
在上面的示例中,实体可以包含任何类型的组件,处理它们的系统可以检索它们所依赖的特定组件,直接访问它们的具体属性,然后修改组件。外部代码还可以向其中一个实体添加一个完全未知的组件,并且不需要更改物理组件来适应它。这与我希望在我的 rust ECS 中具有的行为相同。
作为旁注,由于游戏需要比我的示例 javascript 提供的更高性能的解决方案,我想尽量减少指针间接、哈希表查找、内存分配,并尽可能优化数据局部性,但自然优化仅次于功能。我的示例代码忽略了这些优化。
我一直在尝试的
我考虑过创建
ComponentStorage<T>
的哈希图, 其中 ComponentStorage
是一个特征,它允许我抽象用于存储组件的底层数据结构。一个 State
结构将包含 HashMap<ComponentStorage<std::any::TypeId, T>>
.可以通过 TypeId 哈希查找特定的存储,然后使用 ComponentStorage 特征,我可以检索到 Option<T>
通过实体 ID 从该存储中获取,然后访问任何属性 T
包含。但是,这不起作用,因为
HashMap
中的每个项目的 T 类型都不同。 ,并且我无法通过为类型参数的每个变体创建一个要实现的单个特征来删除类型参数(如这个类似问题中所建议的:Vector of Generic Structs in Rust),因为我需要访问处理系统中的具体类型 T实体。我可以通过使用
Any
来实现类似于我的示例 JavaScript 的东西。存储组件,但我的理解是使用 Any
在任意自定义结构上意味着没有相邻存储和大量指针间接。我并不是要过早地进行优化,但我很犹豫是否沿着这条路线进行原型(prototype)设计,因为它似乎不像 Any
的这些限制。可以在以后不完全重写的情况下克服它。由于指针间接必须显然,为了不将类型硬编码到这个系统中,我希望组件的集合,而不是组件本身,是多态的,同时能够访问给定集合中包含的项目他们的具体类型。
您可以在这里为我提供任何帮助,我将永远感激不尽。谢谢!
最佳答案
只有一种方法可以在同一个容器中拥有不同类型的对象:大量指针间接。
实际上,JavaScript 引擎在幕后为您做完全相同的事情。
关于rust - Rust 中的动态类型实体组件系统,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60133099/