#![feature(test)]
extern crate nalgebra;
extern crate rand;
extern crate shred;
extern crate specs;
extern crate test;
use nalgebra::Vector2;
use rand::thread_rng;
use shred::RunningTime;
use specs::{
prelude::*,
storage::{HashMapStorage, NullStorage},
};
use test::Bencher;
type Vec2 = Vector2<f32>;
#[derive(Clone, Copy, Debug)]
struct Pos(Vec2);
impl Component for Pos {
type Storage = VecStorage<Self>;
}
#[derive(Clone, Copy, Debug)]
struct Vel(Vec2);
impl Component for Vel {
type Storage = VecStorage<Self>;
}
#[derive(Clone, Copy, Debug)]
struct Force(Vec2);
impl Component for Force {
type Storage = VecStorage<Self>;
}
#[derive(Clone, Copy, Debug)]
struct InvMass(f32);
impl Component for InvMass {
type Storage = VecStorage<Self>;
}
#[derive(Clone, Copy, Debug)]
struct Lifetime(f32);
impl Component for Lifetime {
type Storage = VecStorage<Self>;
}
#[derive(Clone, Copy, Debug)]
struct Ball {
radius: f32,
}
impl Component for Ball {
type Storage = VecStorage<Self>;
}
#[derive(Clone, Copy, Debug)]
struct Rect {
a: f32,
b: f32,
}
impl Component for Rect {
type Storage = VecStorage<Self>;
}
#[derive(Clone, Copy, Debug)]
enum Spawner {
Ball { radius: f32, inv_mass: f32 },
Rect { a: f32, b: f32, inv_mass: f32 },
}
impl Component for Spawner {
type Storage = HashMapStorage<Self>;
}
#[derive(Clone, Copy, Debug)]
struct SpawnRequests(usize);
impl Component for SpawnRequests {
type Storage = HashMapStorage<Self>;
}
#[derive(Clone, Copy, Debug)]
struct Collision {
a: Entity,
b: Entity,
contact: Vec2,
}
impl Component for Collision {
type Storage = DenseVecStorage<Self>;
}
#[derive(Clone, Copy, Debug)]
struct Room {
inner_width: f32,
inner_height: f32,
}
impl Component for Room {
type Storage = HashMapStorage<Self>;
}
#[derive(Clone, Copy, Debug)]
enum Color {
Green,
Red,
}
impl Component for Color {
type Storage = VecStorage<Self>;
}
#[derive(Clone, Copy, Debug, Default)]
struct KillsEnemy;
impl Component for KillsEnemy {
type Storage = NullStorage<Self>;
}
#[derive(Clone, Copy, Debug, Default)]
struct DeltaTime(f32);
struct Integrate;
impl<'a> System<'a> for Integrate {
type SystemData = (
WriteStorage<'a, Pos>,
WriteStorage<'a, Vel>,
WriteStorage<'a, Force>,
ReadStorage<'a, InvMass>,
Read<'a, DeltaTime>,
);
fn run(&mut self, (mut pos, mut vel, mut force, inv_mass, delta): Self::SystemData) {
let delta: f32 = delta.0;
for (pos, vel, force, inv_mass) in (&mut pos, &mut vel, &mut force, &inv_mass).join() {
pos.0 += vel.0 * delta;
let damping = (0.9f32).powf(delta);
vel.0 += force.0 * inv_mass.0;
vel.0 *= damping;
force.0 = Vec2::zeros();
}
}
}
struct Spawn;
impl<'a> System<'a> for Spawn {
type SystemData = (
Entities<'a>,
ReadStorage<'a, Spawner>,
WriteStorage<'a, Pos>,
WriteStorage<'a, Vel>,
WriteStorage<'a, Force>,
WriteStorage<'a, InvMass>,
WriteStorage<'a, Ball>,
WriteStorage<'a, Rect>,
WriteStorage<'a, Color>,
WriteStorage<'a, SpawnRequests>,
);
fn run(
&mut self,
(
entities,
spawner,
mut pos,
mut vel,
mut force,
mut inv_mass,
mut ball,
mut rect,
mut color,
mut requests,
): Self::SystemData,
) {
use rand::Rng;
let mut rng = thread_rng();
let mut gen = || rng.gen_range(-4.0, 4.0);
let mut spawns = Vec::new();
for (spawner, pos, color, requests) in (&spawner, &pos, &color, &mut requests).join() {
for _ in 0..requests.0 {
let spawn_pos = Vec2::new(gen(), gen());
let spawn_pos = pos.0 + spawn_pos;
spawns.push((*spawner, spawn_pos, *color));
}
requests.0 = 0;
}
for (spawner, spawn_pos, spawn_color) in spawns {
let entity = entities.create();
let spawn_inv_mass = match spawner {
Spawner::Rect { a, b, inv_mass } => {
rect.insert(entity, Rect { a, b }).unwrap();
inv_mass
}
Spawner::Ball { radius, inv_mass } => {
ball.insert(entity, Ball { radius }).unwrap();
inv_mass
}
};
inv_mass.insert(entity, InvMass(spawn_inv_mass)).unwrap();
pos.insert(entity, Pos(spawn_pos)).unwrap();
vel.insert(entity, Vel(Vec2::new(gen(), gen()))).unwrap();
force.insert(entity, Force(Vec2::zeros())).unwrap();
color.insert(entity, spawn_color).unwrap();
}
}
}
struct RequestSpawns;
impl<'a> System<'a> for RequestSpawns {
type SystemData = WriteStorage<'a, SpawnRequests>;
fn run(&mut self, mut data: Self::SystemData) {
use rand::Rng;
let mut rng = thread_rng();
for requests in (&mut data).join() {
let num = rng.gen_range(0, 200);
if num > 197 {
requests.0 = 2;
}
}
}
}
struct GenCollisions;
impl<'a> System<'a> for GenCollisions {
type SystemData = (
ReadStorage<'a, Pos>,
ReadStorage<'a, Ball>,
ReadStorage<'a, Rect>,
WriteStorage<'a, Collision>,
);
fn run(&mut self, _: Self::SystemData) {
}
fn running_time(&self) -> RunningTime {
RunningTime::VeryShort
}
}
#[bench]
fn bench_parallel(b: &mut Bencher) {
let mut w = World::new();
w.register::<Pos>();
w.register::<Vel>();
w.register::<Force>();
w.register::<InvMass>();
w.register::<Color>();
w.register::<Lifetime>();
w.register::<Ball>();
w.register::<Rect>();
w.register::<Room>();
w.register::<Spawner>();
w.register::<SpawnRequests>();
w.register::<Collision>();
w.insert(DeltaTime(0.02));
for x in -50i32..50i32 {
for y in -50i32..50i32 {
let x = x as f32 * 35.0;
let y = y as f32 * 30.0;
let width = 30.0;
let height = 25.0;
let ball_spawner = Spawner::Ball {
radius: 1.0,
inv_mass: 2.0,
};
let rect_spawner = Spawner::Rect {
a: 1.0,
b: 3.0,
inv_mass: 5.0,
};
let pos_x = [x - 8.0, x - 8.0, x + 8.0, x + 8.0];
let pos_y = [y + 3.0, y - 3.0, y + 3.0, y - 3.0];
let color = [Color::Green, Color::Green, Color::Red, Color::Red];
let spawner = [ball_spawner, rect_spawner, ball_spawner, rect_spawner];
w.create_entity()
.with(Pos(Vec2::new(x, y)))
.with(Room {
inner_width: width,
inner_height: height,
})
.build();
for i in 0..4 {
w.create_entity()
.with(Pos(Vec2::new(pos_x[i], pos_y[i])))
.with(spawner[i])
.with(SpawnRequests(0))
.with(Rect { a: 2.5, b: 2.5 })
.with(color[i])
.build();
}
}
}
let mut d = DispatcherBuilder::new()
.with(RequestSpawns, "req_spawns", &[])
.with(GenCollisions, "gen_collisions", &[])
.with(Spawn, "spawn", &[])
.with(Integrate, "integrate", &[])
.build();
b.iter(|| {
d.dispatch(&mut w);
w.maintain();
})
}