| Crates.io | my-ecs |
| lib.rs | my-ecs |
| version | 0.1.0 |
| created_at | 2024-07-11 10:15:10.843972+00 |
| updated_at | 2025-02-06 01:19:38.702769+00 |
| description | An Entity Component System (ECS) library |
| homepage | |
| repository | https://github.com/ecoricemon/acttey |
| max_upload_size | |
| id | 1299385 |
| size | 1,192,025 |
my-ecs is a library that implements ECS pattern.
Entity Component System (ECS) is a software architecture pattern that breaks
architecture up into data and functions. Component is data of a type and
Entity is a collection of the Components. Lastly, System is a
function. Plus, the crate contains another concept, Resource, which is a
unique data.
The crate provides features below.
Parallel execution by default.
The crate exploits multiple CPU cores for the best performance. Of course
the crate guarantees no data race between systems that access the same
components, entities, or resources. Also, the crate can be collaborated
with rayon's parallel iterator.
Supporting asynchronous function.
The crate contains
Future executor in
it. Therefore, you can put asynchronous IO or compute logics in systems.
Supporting web.
The crate provides web worker implementation and can be built for
'wasm32-unknown-unknown' target. So that you can easily use your native
codebase for the web.
You can declare component types using normal Rust types.
use my_ecs::prelude::*;
#[derive(Component)]
struct Position {
x: u32,
y: u32,
}
Entity is actually kind of an identifier. An entity can be generated by combining components dynamically. But if you declare the entity type in advance, the crate provides you easier ways to access the entity and entity container.
use my_ecs::prelude::*;
#[derive(Component)]
struct Position {
x: u32,
y: u32,
}
// Marker component.
#[derive(Component)]
struct Movable;
#[derive(Entity)]
struct MovableObject {
pos: Position,
movable: Movable,
}
System is a type that accesses components, entities, or resoruces.
use my_ecs::prelude::*;
#[derive(Component)]
struct Position {
x: u32,
y: u32,
}
filter!(Fpos, Target = Position);
fn moves(mut w: Write<Fpos>) {
for Position { x, y } in w.iter_mut().flatten() {
*x += 10;
*y += 10;
}
}
Resource is a unique data.
use my_ecs::prelude::*;
#[derive(Resource)]
struct Count(u32);
Ecs::default(WorkerPool::new(), [])
.add_resource(Count(0))
.add_once_systems((
|rw: ResWrite<Count>| rw.take().0 += 1,
|rr: ResRead<Count>| println!("{}", rr.take().0),
))
.step();
The crate executes systems at the same time over multiple CPU cores by default. The crate analyzes read and write data dependencies between systems then executes them in order without data race. Reads are allowed to be accessed simultaneously while write is exclusive. To do that, clients are required to explicitly state their read or write access.
fn read_components(v: Read<A>) { /* ... */ }
fn write_components(v: Write<B>) { /* ... */ }
fn read_resource(v: ResRead<C>) { /* ... */ }
fn write_resource(v: ResWrite<D>) { /* ... */ }
fn write_entity(v: EntWrite<E>) { /* ... */ }
This is a "hello world" example.
use my_ecs::prelude::*;
#[derive(Component)]
struct Position { x: u32, y: u32 }
#[derive(Component)]
struct Movable;
#[derive(Entity)]
struct Object { pos: Position }
#[derive(Entity)]
struct MovableObject { pos: Position, _m: Movable }
filter!(Fpos, Target = Position);
filter!(Fmovpos, Target = Position, All = Movable);
fn main() {
Ecs::default(WorkerPool::with_len(2), [2])
.register_entity_of::<Object>()
.register_entity_of::<MovableObject>()
.add_once_systems((create, print, moves, print))
.step();
}
fn create(ew: EntWrite<(Object, MovableObject)>) {
let (mut obj_container, mut mov_container) = ew.take_recur();
obj_container.add(Object {
pos: Position { x: 1, y: 2 },
});
mov_container.add(MovableObject {
pos: Position { x: 3, y: 4 },
_m: Movable,
});
}
fn moves(mut w: Write<Fmovpos>) {
for Position { x, y } in w.iter_mut().flatten() {
*x += 10;
*y += 10;
}
}
fn print(r: Read<Fpos>) {
for container in r.iter() {
for Position { x, y } in container.iter() {
println!("{}: ({x}, {y})", container.entity_name().unwrap());
}
}
}