use nightshade_api::prelude::*;
freecs::dynamic_schema! {
pub fn register_game_components {
position: Position => POSITION,
velocity: Velocity => VELOCITY,
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Position(Vec3);
#[derive(Debug, Clone, Copy, Default)]
pub struct Velocity(Vec3);
const COUNT: usize = 24;
const BOUNDS: f32 = 6.0;
const HEIGHT: f32 = 0.6;
fn main() {
run(setup, |world, _| {
integrate(world);
render_sync(world);
})
.unwrap();
}
fn setup(world: &mut World) {
world.ecs.add_world_at(GAME, register_game_components());
let floor = spawn_floor(world, BOUNDS + 1.0);
set_texture(world, floor, "checkerboard");
set_texture_tiling(world, floor, 6.0);
orbit_camera(world, vec3(0.0, 0.0, 0.0), 18.0);
for index in 0..COUNT {
let fraction = index as f32 / COUNT as f32;
let angle = fraction * std::f32::consts::TAU;
let position = vec3(angle.cos() * 4.0, HEIGHT, angle.sin() * 4.0);
let velocity = vec3(angle.sin(), 0.0, -angle.cos()) * 3.0;
let cube = spawn_cube(world, position);
set_color(
world,
cube,
[0.25 + 0.7 * fraction, 0.5, 1.0 - 0.6 * fraction, 1.0],
);
world.set(cube, Position(position));
world.set(cube, Velocity(velocity));
}
}
fn integrate(world: &mut World) {
let delta = delta_time(world);
world
.ecs
.query::<(&mut Position, &mut Velocity)>()
.for_each(|_, (position, velocity)| {
let mut next_velocity = velocity.0;
let mut next_position = position.0 + next_velocity * delta;
for axis in [0, 2] {
if next_position[axis].abs() > BOUNDS {
next_position[axis] = next_position[axis].clamp(-BOUNDS, BOUNDS);
next_velocity[axis] = -next_velocity[axis];
}
}
position.0 = next_position;
velocity.0 = next_velocity;
});
}
fn render_sync(world: &mut World) {
let positions: Vec<(Entity, Vec3)> = world
.query_ref::<&Position>()
.iter()
.map(|(entity, position)| (entity, position.0))
.collect();
for (entity, position) in positions {
set_position(world, entity, position);
}
}