#ecs #consumer #macro #avoiding #inlining #system #entities

nightly ecs-rs

Rust 中一个超级简单的实体-组件系统

3 个版本

使用旧的 Rust 2015

0.1.2 2016 年 3 月 15 日
0.1.1 2016 年 3 月 15 日
0.1.0 2016 年 3 月 15 日

游戏开发 中排名 #1548

GPL-3.0 许可证

11KB
314

ECS.rs

ECS.rs 是用 Rust 编写的实体-组件系统,主要关注在消费者中避免使用宏,同时最小化样板代码。在这里的主要突破是 Rust 的类型和特质系统允许进行完全疯狂的操作。在基于 Any 的虚拟调用中可以使用更多的不安全代码,但除此之外,单态化和内联意味着几乎所有的类型操作仍然意味着代码与手工滚动的样板代码相同。

一个复杂但相当符合现实世界的例子(它来自我的游戏)

struct CameraComponent;
impl SetComponent for CameraComponent {}

struct RenderComponent {
	texture: Texture2d,
	depth: i8,
}
impl SetComponent for RenderComponent {}

struct VelocityComponent(f64, f64);
impl SetComponent for VelocityComponent {}

struct PositionComponent(f64, f64);
impl SetComponent for PositionComponent {}

struct ClipComponent(u32, u32, u32, u32);
impl SetComponent for ClipComponent {}

struct ScaleComponent(f64);
impl SetComponent for ScaleComponent {}

struct RenderSystem;

impl SimpleSystem<(), UpdateData> for RenderSystem {
	type Input = Either<(
		&'static RenderComponent,
		&'static PositionComponent,
		Option<&'static ClipComponent>,
		Option<&'static ScaleComponent>,
	), (
		&'static PositionComponent,
		&'static CameraComponent,
	)>;
	type Output = ();

	fn update(
		&mut self,
		entities: &[
			(
				EntityId,
				Either<(
					&RenderComponent,
					&PositionComponent,
					Option<&ClipComponent>,
					Option<&ScaleComponent>,
				), (
					&PositionComponent,
					&CameraComponent,
				)>
			)
		],
		ud: &UpdateData
	) -> Vec<(EntityId, (), ())> {
		unimplemented!();
	}
}

每个实体都有一个与它关联的异构组件列表。这些组件被设计为纯数据对象,这就是为什么更新接收一个不可变引用而不是可变引用。如果你没有修改给定的组件,你不需要在函数中传递它,这在大多数函数式风格/不可变实体-组件系统中是必须做的。如果你需要更多对实体的控制,例如添加新实体或删除现有实体等,你可以实现 System 而不是 SimpleSystem。

待办事项

  • 允许并行运行 Output=() 系统。这可能会通过创建一个新的 ReadonlySystem 特质,并为其 blanket 实现它来实现,然后让 SystemStore 类型有单独的 mutable 和 readonly 系统列表。也许会有单独的预修改和后修改 RO 系统列表,但这将在我个人需要它时添加。
  • 为 Either&A, B 实现 SetComponent(它将简单地转发到两个中的任意一个)。
  • 使用 impl 特化来实现 SetComponent 对于 T。

没有运行时依赖