#[macro_use] extern crate specs_derive; #[macro_use] extern crate specs_system_macro; use ggez::graphics::Drawable; use specs::prelude::*; use specs::world::WorldExt; mod input; pub mod messages; pub mod util; const WIDTH: f32 = 600.0; const HEIGHT: f32 = 400.0; struct Game { pub world: specs::World, } impl Game { fn setup(conn: messages::Connection) -> Game { let mut world = specs::World::new(); world.register::(); world.register::(); world.register::(); world.register::(); world.insert(input::Input::new()); world.insert(conn); world .create_entity() .with(Pos { x: 200.0, y: 200.0 }) .with(Vel { dx: 0.0, dy: 0.0 }) .with(Controlled) .with(Solid) .build(); Game { world } } } // #[derive(Component, Copy, Clone, Debug)] pub struct Pos { x: f32, y: f32, } #[derive(Component, Debug)] pub struct Vel { dx: f32, dy: f32, } #[derive(Component)] pub struct Controlled; #[derive(Component)] pub struct Solid; system! { Transmit(resource conn: messages::Connection, _c: Controlled, p: Pos) { conn.update(p.x, p.y); } } system! { Control(resource inp: input::Input, _c: Controlled, mut v: Vel) { const ACCEL: f32 = 0.5; v.dx = util::clamp(v.dx + inp.right * ACCEL, -20.0, 20.0); v.dy = util::clamp(v.dy + inp.up * ACCEL, -20.0, 20.0); } } system! { Slowdown(mut v: Vel, _c: Controlled) { const ROUNDING: f32 = 0.01; const FRICTION: f32 = 0.95; if v.dx.abs() < ROUNDING { v.dx = 0.0; } else { v.dx *= FRICTION; } if v.dy.abs() < ROUNDING { v.dy = 0.0; } else { v.dy *= FRICTION; } } } system! { Physics(mut pos: Pos, mut v: Vel, _s: Solid) { if pos.x < 0.0 { pos.x = 0.0; v.dx = v.dx.abs() * 0.5; } else if pos.x > WIDTH { pos.x = WIDTH; v.dx = -v.dx.abs() * 0.5; } if pos.y < 0.0 { v.dy = v.dy.abs(); } else if pos.y > HEIGHT { v.dy = -v.dy.abs(); } } } system! { Move(mut pos: Pos, v: Vel) { pos.x += v.dx; pos.y += v.dy; } } // struct Draw<'t> { pub ctx: &'t mut ggez::Context, } impl<'a, 't> specs::System<'a> for Draw<'t> { type SystemData = (specs::ReadStorage<'a, Pos>,); fn run(&mut self, (pos,): Self::SystemData) { for (p,) in (&pos,).join() { let param = ggez::graphics::DrawParam { dest: [p.x, p.y].into(), ..ggez::graphics::DrawParam::default() }; let mesh = ggez::graphics::Mesh::new_circle( self.ctx, ggez::graphics::DrawMode::fill(), [0.0, 0.0], 10.0, 0.1, ggez::graphics::WHITE, ); mesh.unwrap().draw(self.ctx, param).unwrap(); } } } impl ggez::event::EventHandler for Game { fn draw(&mut self, ctx: &mut ggez::Context) -> ggez::GameResult<()> { ggez::graphics::clear(ctx, ggez::graphics::BLACK); Draw { ctx }.run_now(&self.world); ggez::graphics::present(ctx).unwrap(); Ok(()) } fn update(&mut self, _ctx: &mut ggez::Context) -> ggez::GameResult<()> { Control.run_now(&self.world); Physics.run_now(&self.world); Slowdown.run_now(&self.world); Move.run_now(&self.world); Transmit.run_now(&self.world); Ok(()) } // to handle events, we modify the stored KeyState resource fn key_down_event( &mut self, ctx: &mut ggez::Context, keycode: winit::VirtualKeyCode, _keymod: ggez::event::KeyMods, _repeat: bool, ) { if keycode == winit::VirtualKeyCode::Escape { self.world.read_resource::().goodbye(); ggez::event::quit(ctx); } input::Input::handle_down(&mut self.world.write_resource(), keycode); } fn key_up_event( &mut self, _ctx: &mut ggez::Context, keycode: winit::VirtualKeyCode, _keymod: ggez::event::KeyMods, ) { input::Input::handle_up(&mut self.world.write_resource(), keycode); } } fn main() -> ggez::GameResult<()> { let connection = messages::Connection::new("foo", "192.168.0.3", 9991); let (mut ctx, mut evloop) = ggez::ContextBuilder::new("game", "me") .window_mode(ggez::conf::WindowMode { width: WIDTH, height: HEIGHT, ..ggez::conf::WindowMode::default() }) .build()?; let mut game = Game::setup(connection); let res = ggez::event::run(&mut ctx, &mut evloop, &mut game); res }