Browse Source

Add basic evented motion system

Getty Ritter 4 years ago
parent
commit
c6b7b952cd
2 changed files with 78 additions and 0 deletions
  1. 32 0
      carpet/src/lib.rs
  2. 46 0
      ch2/src/main.rs

+ 32 - 0
carpet/src/lib.rs

@@ -4,6 +4,9 @@ use ggez::{Context, GameError};
 use specs::WorldExt;
 use std::path::Path;
 
+pub use winit::VirtualKeyCode;
+pub use ggez::input::keyboard::KeyMods;
+
 #[derive(Eq, PartialEq, Debug, Copy, Clone)]
 pub enum Color {
     Red,
@@ -212,9 +215,12 @@ impl Board<CP437> {
 }
 
 type Updater = Box<dyn FnMut(&mut specs::World)>;
+type Keycode = (winit::VirtualKeyCode, ggez::event::KeyMods);
+type EventMap = std::collections::HashMap<Keycode, Updater>;
 pub struct World<Idx> {
     pub world: specs::World,
     updater: Updater,
+    events: EventMap,
     idx: std::marker::PhantomData<Idx>,
 }
 
@@ -227,9 +233,11 @@ impl<Idx: Tile + 'static> World<Idx> {
         let mut world = specs::World::new();
         world.insert(board);
         let updater = do_nothing();
+        let events = std::collections::HashMap::new();
         World {
             world,
             updater,
+            events,
             idx: std::marker::PhantomData,
         }
     }
@@ -255,6 +263,10 @@ impl<Idx: Tile + 'static> World<Idx> {
     pub fn on_update(&mut self, update: impl FnMut(&mut specs::World) + 'static) {
         self.updater = Box::new(update) as Updater;
     }
+
+    pub fn on_keycode(&mut self, kc: Keycode, update: impl FnMut(&mut specs::World) + 'static) {
+        self.events.insert(kc, Box::new(update) as Updater);
+    }
 }
 
 impl World<CP437> {
@@ -277,6 +289,21 @@ impl<Idx: 'static + Tile> ggez::event::EventHandler for World<Idx> {
         std::mem::swap(&mut updater, &mut self.updater);
         Ok(())
     }
+
+    fn key_down_event(
+        &mut self,
+        ctx: &mut Context,
+        keycode: winit::VirtualKeyCode,
+        keymod: ggez::event::KeyMods,
+        _repeat: bool,
+    ) {
+        if keycode == VirtualKeyCode::Escape {
+            ggez::event::quit(ctx);
+        }
+        if let Some(cb) = self.events.get_mut(&(keycode, keymod)) {
+            cb(&mut self.world);
+        }
+    }
 }
 
 //
@@ -313,6 +340,11 @@ impl<Idx: Tile + 'static> Game<Idx> {
         self.world.world.create_entity()
     }
 
+
+    pub fn on_key(&mut self, kc: Keycode, update: impl FnMut(&mut specs::World) + 'static) {
+        self.world.on_keycode(kc, update);
+    }
+
     pub fn run(self) -> ggez::GameResult<()> {
         let Game {
             mut world,

+ 46 - 0
ch2/src/main.rs

@@ -21,6 +21,15 @@ pub struct Renderable {
 #[derive(Component)]
 pub struct MoveLeft;
 
+#[derive(Component)]
+pub struct Player;
+
+#[derive(Component)]
+pub struct Motion {
+    down: i8,
+    right: i8,
+}
+
 system_impl! {
     Draw(
         resource mut board: carpet::Board<carpet::CP437>,
@@ -47,6 +56,18 @@ system! {
     }
 }
 
+system! {
+    Move (
+        mut motion: Motion,
+        mut pos: Pos,
+    ) {
+        pos.x = (pos.x as i8 + motion.right) as usize;
+        pos.y = (pos.y as i8 + motion.down) as usize;
+    } finally {
+        motion.clear();
+    }
+}
+
 fn main() -> Result<(), GameError> {
     let mut game = carpet::GameBuilder::new()
         .name("game")
@@ -64,10 +85,13 @@ fn main() -> Result<(), GameError> {
     game.register::<Pos>();
     game.register::<Renderable>();
     game.register::<MoveLeft>();
+    game.register::<Motion>();
+    game.register::<Player>();
     game.world.print([1, 1], "Hello, world!");
 
     game.create_entity()
         .with(Pos { x: 40, y: 25 })
+        .with(Player)
         .with(Renderable {
             glyph: carpet::CP437::from_char('A'),
             color: carpet::Color::Blue,
@@ -84,8 +108,30 @@ fn main() -> Result<(), GameError> {
             .with(MoveLeft)
             .build();
     }
+
+    game.on_key((carpet::VirtualKeyCode::W, carpet::KeyMods::NONE), |world| {
+        let player = (&world.read_component::<Player>(), &world.entities()).join().next().unwrap().1;
+        world.write_component::<Motion>().insert(player, Motion { down: -1, right: 0 }).unwrap();
+    });
+
+    game.on_key((carpet::VirtualKeyCode::A, carpet::KeyMods::NONE), |world| {
+        let player = (&world.read_component::<Player>(), &world.entities()).join().next().unwrap().1;
+        world.write_component::<Motion>().insert(player, Motion { down: 0, right: -1 }).unwrap();
+    });
+
+    game.on_key((carpet::VirtualKeyCode::S, carpet::KeyMods::NONE), |world| {
+        let player = (&world.read_component::<Player>(), &world.entities()).join().next().unwrap().1;
+        world.write_component::<Motion>().insert(player, Motion { down: 1, right: 0 }).unwrap();
+    });
+
+    game.on_key((carpet::VirtualKeyCode::D, carpet::KeyMods::NONE), |world| {
+        let player = (&world.read_component::<Player>(), &world.entities()).join().next().unwrap().1;
+        world.write_component::<Motion>().insert(player, Motion { down: 0, right: 1 }).unwrap();
+    });
+
     game.run_with_systems(|world| {
         Draw.run_now(&world);
         Leftward.run_now(&world);
+        Move.run_now(&world);
     })
 }