Skip to content

Commit

Permalink
Refactor to ECS using specs
Browse files Browse the repository at this point in the history
  • Loading branch information
andreivasiliu committed May 1, 2018
1 parent 5e1c20c commit 30b4113
Show file tree
Hide file tree
Showing 8 changed files with 396 additions and 114 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -3,4 +3,5 @@
**/*.rs.bk
Cargo.lock
state.json
storage.ron
.idea
3 changes: 3 additions & 0 deletions Cargo.toml
Expand Up @@ -12,3 +12,6 @@ failure = "*"
serde_derive = "*"
serde_json = "*"
serde = "*"
specs = { version = "0.11.0-alpha5", features = ["serde"] }
specs-derive = "0.2"
ron = "*"
48 changes: 48 additions & 0 deletions src/animate.rs
@@ -0,0 +1,48 @@
extern crate specs;

use specs::prelude::{VecStorage, System, WriteStorage, Entities, Join};
use std::marker::PhantomData;

#[derive(Component, Debug, Serialize, Deserialize, Clone)]
#[storage(VecStorage)]
pub struct Animation<T>
where T: Sync + Send + 'static {
pub current: u32,
pub limit: u32,

#[serde(skip)]
phantom: PhantomData<T>,
}

impl<T> Animation<T>
where T: Sync + Send + 'static {
pub fn new(limit: u32) -> Self {
Animation {
current: 0,
limit,
phantom: PhantomData::default(),
}
}
}

pub struct UpdateAnimations;

impl <'a> System<'a> for UpdateAnimations {
type SystemData = (
Entities<'a>,
WriteStorage<'a, Animation<RoomAnimation>>
);

fn run(&mut self, (entities, mut room_animations): Self::SystemData) {
for (_entity, animation) in (&*entities, &mut room_animations).join() {
if animation.current < animation.limit {
animation.current += 1;
} else {
// remove animation from entity
}
}
}
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
pub struct RoomAnimation {}
136 changes: 136 additions & 0 deletions src/draw.rs
@@ -0,0 +1,136 @@
extern crate opengl_graphics;
extern crate specs;

use specs::prelude::{World, VecStorage, ReadStorage, ReadExpect, Join, System, Entities, RunNow};
use piston::input::RenderArgs;
use opengl_graphics::GlGraphics;
use MouseInput;
use animate::{Animation, RoomAnimation};

#[derive(Debug, Component, Serialize, Deserialize, Clone, Copy)]
#[storage(VecStorage)]
pub struct Position {
pub x: i32,
pub y: i32,
}

#[derive(Component, Debug, Serialize, Deserialize, Clone, Copy)]
#[storage(VecStorage)]
pub struct Size {
pub width: i32,
pub height: i32,
}

//#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
//pub struct Animator {
// current: u32,
// limit: u32,
//}

fn rectangle_to_lines(rect: [f64; 4]) -> [[f64; 4]; 4] {
let x1 = rect[0];
let y1 = rect[1];
let x2 = rect[0] + rect[2];
let y2 = rect[1] + rect[3];

[
[x1, y1, x2, y1],
[x2, y1, x2, y2],
[x2, y2, x1, y2],
[x1, y2, x1, y1],
]
}

pub struct ClearScreen<'a> {
pub gl_graphics: &'a mut GlGraphics,
pub render_args: RenderArgs,
}

impl <'a, 'b> System<'a> for ClearScreen<'b> {
type SystemData = ();

fn run(&mut self, (): Self::SystemData) {
use graphics::clear;

self.gl_graphics.draw(self.render_args.viewport(), |_context, gl| {
clear([0.0, 0.0, 0.0, 1.0], gl);
});
}
}

pub struct DrawRooms<'a> {
pub gl_graphics: &'a mut GlGraphics,
pub render_args: RenderArgs,
}

impl <'a, 'b> System<'a> for DrawRooms<'b> {
type SystemData = (
Entities<'a>,
ReadStorage<'a, Position>,
ReadStorage<'a, Size>,
ReadStorage<'a, Animation<RoomAnimation>>,
);

fn run(&mut self, (entities, positions, sizes, animations): Self::SystemData) {
for (_entity, position, size, animation) in (&*entities, &positions, &sizes, &animations).join() {
if size.width < 5 || size.height < 5 {
continue;
}

let room_rectangle = [
position.x as f64, position.y as f64,
size.width as f64, size.height as f64,
];

let brightness = 0.25 + 0.75 * ((32 - animation.current) as f32 / 32.0);
let color = [brightness, brightness, brightness, 1.0];

self.gl_graphics.draw(self.render_args.viewport(), |context, gl| {
use graphics::line;

// rectangle([0.2, 0.2, 0.5, 0.01], room_rectangle, context.transform, gl);

for l in rectangle_to_lines(room_rectangle).iter() {
line(color, 0.5, *l, context.transform, gl);
}
});
}
}
}

pub struct DrawSelectionBox<'a> {
pub gl_graphics: &'a mut GlGraphics,
pub render_args: RenderArgs,
}

impl <'a, 'b> System<'a> for DrawSelectionBox<'b> {
type SystemData = ReadExpect<'a, MouseInput>;

fn run(&mut self, mouse_input: Self::SystemData) {
self.gl_graphics.draw(self.render_args.viewport(), |context, gl| {
if mouse_input.dragging {
use graphics::{rectangle, line};

let rect = mouse_input.selection_rectangle_f64();

rectangle([0.25, 1.0, 0.25, 0.01], rect, context.transform, gl);
for l in rectangle_to_lines(rect).iter() {
line([0.25, 1.0, 0.25, 1.0], 0.5, *l, context.transform, gl);
}
}
});
}
}

pub fn run_draw_systems(specs_world: &mut World,
gl_graphics: &mut GlGraphics,
render_args: RenderArgs) {
ClearScreen { gl_graphics, render_args }
.run_now(&mut specs_world.res);

DrawRooms { gl_graphics, render_args }
.run_now(&mut specs_world.res);

DrawSelectionBox { gl_graphics, render_args }
.run_now(&mut specs_world.res);
}
8 changes: 8 additions & 0 deletions src/error.rs
@@ -0,0 +1,8 @@
pub use failure::{Error, ResultExt};

#[derive(Debug, Fail)]
pub enum GameError {
#[fail(display = "cannot create game window: {}", reason)]
WindowError { reason: String }
}

Empty file added src/input.rs
Empty file.

0 comments on commit 30b4113

Please sign in to comment.