11个版本
0.2.2 | 2024年5月1日 |
---|---|
0.2.1 | 2024年5月1日 |
0.1.7 | 2024年4月30日 |
#346 在 游戏开发
每月 31 次下载
13KB
Nate-Engine
描述
Nate-Engine 是我在无聊时正在开发的一个概念项目。主要概念是 Nate-Engine 是一个基于实体组件系统(ECS)模型的游戏引擎。我可能用它来制作几个 tui 游戏,但我强烈建议不要用它,因为它纯粹是一个测试,大多数真实项目可能应该使用类似 bevy 的工具。
目标
项目的目标是通过几个宏来创建非常容易的 ECS 系统
组件
组件宏应该使定义项目中使用的组件列表变得简单。可能还有一些只对每个实体使用一次的单一项目。可能如下所示
#[world(singular=[canvas])]
pub struct World {
position: (f32, f32),
player_velocity: (f32, f32),
object_velocity: (f32, f32),
sprite: Sprite,
canvas: [[bool; 10]; 10],
}
它翻译成
pub struct World {
entities: Arc<RwLock<Vec<u32>>>,
pub canvas: Arc<RwLock<Option<[[bool; 10]; 10]>>>,
pub position: Arc<RwLock<Vec<Option<(f32, f32)>>>>,
pub player_velocity: Arc<RwLock<Vec<Option<(f32, f32)>>>>,
pub object_velocity: Arc<RwLock<Vec<Option<(f32, f32)>>>>,
pub sprite: Arc<RwLock<Vec<Option<Sprite>>>>,
}
系统
对于系统,我希望自动生成迭代器 + 过滤器,这样在 proc-macro 中,用户只需要指定应该有哪些字段,以及一个可选的过滤参数。例如
#[system(world=DinosaurWorld, read=[object_velocity], write=position)]
fn position_update_system() {
*position = (position.0 + object_velocity.0, position.1 + object_velocity.1);
}
它将扩展为
fn position_update_system(world: Arc<DinosaurWorld>) {
let object_velocity = world.object_velocity.read().unwrap();
let mut position = world.positions.write().unwrap();
for (object_velocity, position) in object_velocity.iter().zip(position.iter_mut()).filter(|v| v.0.is_some() && v.1.is_some()) {
let object_velocity = object_velocity.as_ref().unwrap();
let mut position = position.as_mut().unwrap();
position = (position.0 + object_velocity.0, position.1 + object_velocity.1);
}
}
也可能非常有用,添加某种类型的过滤器,允许用户过滤的不仅仅是某些组件存在,还可以是组件具有某些值。例如以下情况
#[world]
pub struct World {
position: (u32, u32),
damage_zone: (u32, u32),
health: u32,
}
#[system(
world=World,
write=[health],
read=[position, damage_zone],
filter="position == damage_zone"
)]
fn position_damage_system() {
health -= 1;
}
它将扩展为
pub struct World {
entities: Arc<RwLock<Vec<u32>>>,
positions: Arc<RwLock<Vec<Option<(u32, u32)>>>>,
damage_zones: Arc<RwLock<Vec<Option<(u32, u32)>>>>,
healths: Arc<RwLock<Vec<Option<u32>>>>,
}
fn position_damage_system(world: Arc<World>) {
let positions = world.positions.read().unwrap();
let damage_zones = world.damage_zones.read().unwrap();
let mut healths = world.healths.write().unwrap();
for ((_position, _damage_zone), health) in positions.iter().zip(damage_zones.iter()).zip(healths.iter_mut()).filter(|v| v.0.0.is_some() && v.0.1.is_some() && v.1.is_some() && v.0.0 == v.0.1) {
*health -= 1
}
}
还可以通过使用 _read 和 _write 作为它们的标识符来在系统中引用单个组件。例如
#[system(world=World, _read=[canvas], _write=[exit])]
fn read_canvas_and_exit() {
...
}
这将允许用户通过读取访问画布并写入退出
项目
以下是使用该游戏引擎的项目列表。
- td-tui:一个基于终端的塔防迷你游戏。
依赖项
~1.9–9.5MB
~91K SLoC