use flax::{
component, entity_ids, CommandBuffer, Component, Debuggable, Entity, EntityBorrow, FetchExt,
Mutable, Query, QueryBorrow, Schedule, System, World,
};
use glam::{vec2, Vec2};
use rand::{rngs::StdRng, Rng, SeedableRng};
fn main() -> anyhow::Result<()> {
let mut world = World::new();
component! {
position: Vec2 => [ Debuggable ],
health: f32 => [ Debuggable ],
}
let id = Entity::builder()
.set(position(), vec2(1.0, 4.0))
.set(health(), 75.0)
.spawn(&mut world);
let id2 = Entity::builder()
.set(position(), vec2(-1.0, 4.0))
.set(health(), 75.0)
.spawn(&mut world);
let mut query = Query::new((position(), health()));
for (pos, health) in &mut query.borrow(&world) {
println!("pos: {pos:?}, health: {health}");
}
component! {
distance: f32 => [ flax::Debuggable ],
}
println!("Spawning id3");
let id3 = world.spawn();
world.set(id3, position(), vec2(5.0, 6.0))?;
world.set(id3, health(), 5.0)?;
for id in [id, id2, id3] {
println!("Adding distance to {id}");
world.set(id, distance(), 0.0)?;
}
let mut query = Query::new((entity_ids(), position(), distance().as_mut()))
.filter(position().modified() & health().gt(0.0));
println!("Updating distances");
for (id, pos, dist) in &mut query.borrow(&world) {
println!("Updating distance for {id} with position: {pos:?}");
*dist = pos.length();
}
println!("Running query again");
for (id, pos, dist) in &mut query.borrow(&world) {
println!("Updating distance for {id} with position: {pos:?}");
*dist = pos.length();
}
*world.get_mut(id2, position())? = vec2(8.0, 3.0);
println!("... and again");
for (id, pos, dist) in &mut query.borrow(&world) {
println!("Updating distance for {id} with position: {pos:?}");
*dist = pos.length();
}
#[allow(unused_variables)]
{
let query = Query::new((position(), health(), distance()))
.filter(position().modified() & health().modified());
let query = Query::new((position().modified(), health().modified(), distance()));
}
let mut update_distance = System::builder()
.with_name("update_distance")
.with_query(query)
.build(
|mut query: QueryBorrow<(_, Component<Vec2>, Mutable<f32>), _>| {
for (id, pos, dist) in &mut query {
println!("Updating distance for {id} with position: {pos:?}");
*dist = pos.length();
}
},
);
update_distance.run(&mut world);
let mut update_dist = System::builder()
.with_name("update_distance")
.with_query(
Query::new((entity_ids(), position(), distance().as_mut()))
.filter(position().modified()),
)
.for_each(|(id, pos, dist)| {
tracing::debug!("Updating distance for {id} with position: {pos:?}");
*dist = pos.length();
});
for _ in 0..16 {
update_dist.run(&mut world);
}
let despawn = System::builder()
.with_name("delete_outside_world")
.with_query(Query::new((entity_ids(), distance())).filter(distance().gt(50.0)))
.with_cmd_mut()
.build(|mut q: QueryBorrow<_, _>, cmd: &mut CommandBuffer| {
for (id, &dist) in &mut q {
println!("Despawning {id} at: {dist}");
cmd.despawn(id);
}
});
let debug_world = System::builder()
.with_name("debug_world")
.with_world()
.build(|world: &_| {
tracing::debug!("World: {world:?}");
});
component! {
is_static: () => [ flax::Debuggable ],
}
let mut rng = StdRng::seed_from_u64(42);
for _ in 0..150 {
let pos = vec2(rng.gen_range(-5.0..5.0), rng.gen_range(-5.0..5.0));
Entity::builder()
.set(position(), pos)
.set_default(distance())
.set_default(is_static())
.spawn(&mut world);
}
let move_out = System::builder()
.with_name("move_out")
.with_query(Query::new(position().as_mut()).filter(is_static().without()))
.for_each(|pos| {
let dir = pos.normalize_or_zero();
*pos += dir;
});
let spawn = System::builder().with_name("spawner").with_cmd_mut().build(
move |cmd: &mut CommandBuffer| {
for _ in 0..100 {
let pos = vec2(rng.gen_range(-10.0..10.0), rng.gen_range(-10.0..10.0));
println!("Spawning new entity at: {pos:?}");
Entity::builder()
.set(position(), pos)
.set_default(distance())
.spawn_into(cmd);
}
},
);
let mut frame_count = 0;
let count = System::builder()
.with_name("count")
.with_query(Query::new(()))
.build(move |mut query: QueryBorrow<()>| {
let count: usize = query.iter_batched().map(|v| v.len()).sum();
println!("[{frame_count}]: {count}");
frame_count += 1;
});
let mut schedule = Schedule::builder()
.with_system(update_dist)
.with_system(despawn)
.with_system(spawn)
.with_system(move_out)
.with_system(debug_world)
.with_system(count)
.build();
println!("{schedule:#?}");
for i in 0..20 {
println!("Frame: {i}");
println!("Batches: {:#?}", schedule.batch_info(&world));
schedule.execute_par(&mut world)?;
}
component! {
window_width: f32,
window_height: f32,
allow_vsync: bool,
resources,
}
Entity::builder()
.set(window_width(), 800.0)
.set(window_height(), 600.0)
.set(allow_vsync(), false)
.append_to(&mut world, resources())
.unwrap();
let mut query = Query::new((window_width(), window_height(), allow_vsync()))
.entity(resources());
let mut borrow = query.borrow(&world);
let (width, height, vsync) = borrow.get().unwrap();
println!("width: {width} height: {height}, vsync: {vsync}");
drop(borrow);
let mut window_system = System::builder()
.with_query(query)
.build(|mut q: EntityBorrow<_>| {
if let Ok((width, height, allow_vsync)) = q.get() {
println!(
"Config changed width: {width}, height: {height}, allow_vsync: {allow_vsync}"
);
} else {
println!("No config change");
}
});
window_system.run(&mut world);
window_system.run(&mut world);
world.set(resources(), window_height(), 720.0)?;
window_system.run(&mut world);
Ok(())
}