#ecs #gamedev

kiwi-ecs

一个高性能、小型且通用的实体组件系统

11个稳定版本

1.4.1 2023年2月24日
1.4.0 2023年2月21日
1.3.1 2022年11月18日
1.2.2 2022年10月31日

游戏开发类别中排名#294

MIT许可

35KB
643

kiwi ecs

一个高性能、无依赖的ECS库,具有良好的API,用Rust编写。

用法

# Cargo.toml

[dependecies]
kiwi-ecs = "1.3"
// lib.rs
use kiwi_ecs::*;

世界

首先,创建一个新的World。这是ecs的起点。程序可以有多个独立的世界。

pub fn main() {
  let mut world = World::new();
}

组件

组件定义如下

#[derive(Component)]
struct Position {
  x: u32,
  y: u32
}

标志

单元结构不能用作组件,这是您需要使用标志的地方。标志表示为一个枚举

#[flags]
enum Flags {
  Player,
  Enemy,
  Ground,
}

实体

要创建具有给定组件的新实体

// spawn_entity macro accepts the world as the first parameter, and the 
// components to add to the entity as the other parameters
let entity_id = spawn_entity!(world, Position { x: 0, y: 0 });

您可以使用set_flag方法给实体一个标志

world.set_flag(entity_id, Flags::Player);

系统

定义系统有两种方式。

第一种是使用system

// immutable system
#[system(pos: Position)]
fn print_positions(world: &World) {
  println!("{:?}", pos);
}

// mutable system
#[system(pos: Position, vel: Vel)]
fn move_entities(world: &mut World) {
  pos.x += vel.x;
  pos.y += vel.y
}

// query entity ids as well
#[system(id: EntityId, pos: Position)]
/// prints all entities ids having the position component
fn print_entity_ids(world: &World) {
  println!("{id}");
}

pub fn main() {
  let mut world = World::new();
  
  //--snip
  
  // Call the systems
  print_positions(&world);
  move_entities(&mut world);
  print_entity_ids(&world);
}

要创建一个可变系统,函数应将其第一个参数作为world: &mut World,对于不可变的一个,添加world: &World

函数可以包含任何数量的您可以在调用时传递给它的参数。

函数可以返回任何类型的Result<(), Any>。如果此函数具有给定的结果返回类型,则在系统结束时将返回Ok(())

第二种是使用queryquery_mut

pub fn main() {
  let mut world = World::new();
  
  //--snip
  
  let query_result = query!(world, Position);
  let query_result = query_mut!(world, Position, Velocity);
  let query_result = query!(world, EntityId, Position);
  
  // You can now loop over the components
  query_result.for_each(|components| {
    // ...
  });
}

查询中的标志

您可以使用标志进一步过滤查询

#[system(id: EntityId, pos: Position)]
fn on_player(world: &World) {
  if world.has_flag(id, Flags::Player) {
    // ...
  }
}

let query_result = query!(world, EntityId, Position)
  .filter(|(id, _pos)| world.has_flag(*id, Flags::Player));

特性标志

try

此crate的try功能允许在系统中提前返回。

要启用它

# Cargo.toml

[dependencies]
kiwi-ecs = { version = "*", features = ["try"] }
用法

使用try标记返回类型为Result的ok类型()的系统

#[system(try, id: EntityId, pos: Position)]
fn a_system_with_a_fallible_condition(world: &World) -> Result<(), String> {
  let mesh = get_mesh(id)?; // fallible function
  render(mesh, pos)?;
}

除了返回 Err 外,您还可以使用 return std::ops::ControlFlow::Continue(()) 来跳过当前实体并继续到下一个,或者使用 return std::ops::ControlFlow::Break(()) 来在没有错误的情况下跳出函数。

贡献

欢迎贡献者。如果您发现任何错误,请随意提出问题。如果您愿意,PR 也会受到赞赏!

许可证

MIT 许可证下授权。

依赖项

~1.5MB
~35K SLoC