Refactor input usage into two separate systems, barebones physics
    
    
      
        Getty Ritter
        6 years ago
      
    
    
  
  
  | 649 | 649 | ] | 
| 650 | 650 | |
| 651 | 651 | [[package]] | 
| 652 | name = "jeffersonia" | |
| 653 | version = "0.1.0" | |
| 654 | dependencies = [ | |
| 655 | "ggez 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", | |
| 656 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", | |
| 657 | "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", | |
| 658 | "specs 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)", | |
| 659 | "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | |
| 660 | "tiled 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", | |
| 661 | ] | |
| 662 | ||
| 663 | [[package]] | |
| 664 | 652 | name = "jpeg-decoder" | 
| 665 | 653 | version = "0.1.15" | 
| 666 | 654 | source = "registry+https://github.com/rust-lang/crates.io-index" | 
| 1661 | 1649 | name = "void" | 
| 1662 | 1650 | version = "1.0.2" | 
| 1663 | 1651 | source = "registry+https://github.com/rust-lang/crates.io-index" | 
| 1652 | ||
| 1653 | [[package]] | |
| 1654 | name = "wenaglia" | |
| 1655 | version = "0.1.0" | |
| 1656 | dependencies = [ | |
| 1657 | "ggez 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", | |
| 1658 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", | |
| 1659 | "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", | |
| 1660 | "specs 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)", | |
| 1661 | "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | |
| 1662 | "tiled 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", | |
| 1663 | ] | |
| 1664 | 1664 | |
| 1665 | 1665 | [[package]] | 
| 1666 | 1666 | name = "which" | 
| 54 | 54 | } | 
| 55 | 55 | } | 
| 56 | 56 | |
| 57 | ||
| 58 | 57 | #[derive(Component, Default, Debug)] | 
| 59 | 58 | #[storage(NullStorage)] | 
| 60 | 59 | pub struct Background; | 
| 1 | use sdl2::keyboard as sdl; | |
| 2 | ||
| 3 | /// The shared values that the game state needs, mostly contained in | |
| 4 | /// the specs ECS world | |
| 5 | pub struct MyGame { | |
| 6 | pub world: specs::World, | |
| 7 | pub sprites: ggez::graphics::spritebatch::SpriteBatch, | |
| 8 | pub keys: std::collections::HashSet<sdl::Keycode>, | |
| 9 | } | 
| 1 | 1 | #[macro_use] extern crate specs_derive; | 
| 2 | 2 | |
| 3 | use ggez::{Context, ContextBuilder, GameResult}; | |
| 4 | use ggez::event::{self, EventHandler}; | |
| 5 | use ggez::graphics; | |
| 6 | ||
| 7 | 
                  use  | 
              |
| 3 | use ggez::{ | |
| 4 | Context, | |
| 5 | ContextBuilder, | |
| 6 | GameResult, | |
| 7 | event::{self, EventHandler}, | |
| 8 | }; | |
| 8 | 9 | |
| 9 | 10 | use sdl2::keyboard as sdl; | 
| 10 | 11 | |
| 11 | 12 | pub mod consts; | 
| 12 | 13 | pub mod components; | 
| 14 | pub mod game; | |
| 13 | 15 | pub mod res; | 
| 14 | 16 | pub mod sys; | 
| 15 | 17 | |
| 16 | struct MyGame { | |
| 17 | world: specs::World, | |
| 18 | sprites: graphics::spritebatch::SpriteBatch, | |
| 19 | } | |
| 18 | use game::MyGame; | |
| 20 | 19 | |
| 21 | 20 | impl EventHandler for MyGame { | 
| 22 | 21 | |
| 23 | 22 | fn update(&mut self, _ctx: &mut Context) -> GameResult<()> { | 
| 23 | sys::input::systems(self); | |
| 24 | sys::physics::systems(self); | |
| 24 | 25 | Ok(()) | 
| 25 | 26 | } | 
| 26 | 27 | |
| 27 | 28 | fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { | 
| 28 | ggez::graphics::set_background_color(ctx, ggez::graphics::BLACK); | |
| 29 | ggez::graphics::clear(ctx); | |
| 30 | ||
| 31 | sys::Draw { | |
| 32 | ctx, | |
| 33 | sprites: &mut self.sprites, | |
| 34 | _phase: components::Background, | |
| 35 | }.run_now(&self.world.res); | |
| 36 | sys::Draw { | |
| 37 | ctx, | |
| 38 | sprites: &mut self.sprites, | |
| 39 | _phase: components::Foreground, | |
| 40 | }.run_now(&self.world.res); | |
| 41 | sys::Draw { | |
| 42 | ctx, | |
| 43 | sprites: &mut self.sprites, | |
| 44 | _phase: components::Decoration, | |
| 45 | }.run_now(&self.world.res); | |
| 46 | ||
| 47 | ggez::graphics::draw( | |
| 48 | ctx, | |
| 49 | &self.sprites, | |
| 50 | ggez::nalgebra::Point2::new(0.0, 0.0), | |
| 51 | 0.0 | |
| 52 | )?; | |
| 53 | self.sprites.clear(); | |
| 54 | ggez::graphics::present(ctx); | |
| 55 | Ok(()) | |
| 29 | sys::drawing::systems(self, ctx) | |
| 56 | 30 | } | 
| 57 | 31 | |
| 58 | 32 | fn key_down_event( | 
| 65 | 39 | if keycode == sdl::Keycode::Escape { | 
| 66 | 40 | ctx.quit().expect("Should never fail"); | 
| 67 | 41 | } | 
| 68 | 
                          s | 
              |
| 42 | self.keys.insert(keycode); | |
| 43 | } | |
| 44 | ||
| 45 | fn key_up_event( | |
| 46 | &mut self, | |
| 47 | _ctx: &mut Context, | |
| 48 | keycode: sdl::Keycode, | |
| 49 | _keymod: sdl::Mod, | |
| 50 | _repeat: bool, | |
| 51 | ) { | |
| 52 | self.keys.remove(&keycode); | |
| 69 | 53 | } | 
| 70 | 54 | } | 
| 71 | 55 | |
| 89 | 73 | ..Default::default() | 
| 90 | 74 | }) | 
| 91 | 75 | .build()?; | 
| 92 | let image = graphics::Image::new(&mut ctx, "/spritesheet.png")?; | |
| 93 | let mut sprites = graphics::spritebatch::SpriteBatch::new(image); | |
| 76 | let image = ggez::graphics::Image::new(&mut ctx, "/spritesheet.png")?; | |
| 77 | let mut sprites = ggez::graphics::spritebatch::SpriteBatch::new(image); | |
| 94 | 78 | sprites.set_filter(ggez::graphics::FilterMode::Nearest); | 
| 79 | let keys = std::collections::HashSet::new(); | |
| 95 | 80 | |
| 96 | 81 | let mut my_game = MyGame { | 
| 97 | 82 | world, | 
| 98 | 83 | sprites, | 
| 84 | keys, | |
| 99 | 85 | }; | 
| 100 | 86 | |
| 101 | 87 | event::run(&mut ctx, &mut my_game) | 
| 17 | 17 | DrawLayer::Foreground, | 
| 18 | 18 | DrawLayer::Decoration, | 
| 19 | 19 | ]; | 
| 20 | ||
| 21 | 20 | |
| 22 | 21 | pub fn world_from_file<P: AsRef<Path>>(w: &mut specs::World, path: P) { | 
| 23 | 22 | let tiled::Map { | 
| 1 | 1 | use crate::consts; | 
| 2 | 
                  use crate::components::{ | 
              |
| 2 | use crate::components::{self,Position,Sprite}; | |
| 3 | use crate::game::MyGame; | |
| 3 | 4 | |
| 4 | 5 | use ggez::{ | 
| 5 | 6 | Context, | 
| 7 | graphics, | |
| 6 | 8 | graphics::spritebatch::SpriteBatch, | 
| 7 | 9 | }; | 
| 8 | 
                  use  | 
              |
| 10 | use specs::RunNow; | |
| 9 | 11 | |
| 12 | /// The `Draw` system is parameterized by which phase we want to draw | |
| 13 | /// in. | |
| 10 | 14 | pub struct Draw<'t, Phase> { | 
| 11 | 15 | pub ctx: &'t mut Context, | 
| 12 | 16 | pub sprites: &'t mut SpriteBatch, | 
| 13 | 17 | pub _phase: Phase, | 
| 14 | 18 | } | 
| 15 | 19 | |
| 16 | 
                  impl<'a, 't, Phase | 
              |
| 20 | impl<'a, 't, Phase : specs::Component> specs::System<'a> for Draw<'t, Phase> { | |
| 17 | 21 | type SystemData = ( | 
| 18 | 22 | specs::ReadStorage<'a, Position>, | 
| 19 | 23 | specs::ReadStorage<'a, Sprite>, | 
| 40 | 44 | } | 
| 41 | 45 | } | 
| 42 | 46 | } | 
| 47 | ||
| 48 | ||
| 49 | pub fn systems(game: &mut MyGame, ctx: &mut Context) -> ggez::GameResult<()> { | |
| 50 | graphics::set_background_color(ctx, graphics::BLACK); | |
| 51 | graphics::clear(ctx); | |
| 52 | ||
| 53 | Draw { | |
| 54 | ctx, | |
| 55 | sprites: &mut game.sprites, | |
| 56 | _phase: components::Background, | |
| 57 | }.run_now(&game.world.res); | |
| 58 | Draw { | |
| 59 | ctx, | |
| 60 | sprites: &mut game.sprites, | |
| 61 | _phase: components::Foreground, | |
| 62 | }.run_now(&game.world.res); | |
| 63 | Draw { | |
| 64 | ctx, | |
| 65 | sprites: &mut game.sprites, | |
| 66 | _phase: components::Decoration, | |
| 67 | }.run_now(&game.world.res); | |
| 68 | ||
| 69 | graphics::draw( | |
| 70 | ctx, | |
| 71 | &game.sprites, | |
| 72 | ggez::nalgebra::Point2::new(0.0, 0.0), | |
| 73 | 0.0 | |
| 74 | )?; | |
| 75 | game.sprites.clear(); | |
| 76 | graphics::present(ctx); | |
| 77 | Ok(()) | |
| 78 | } | |
| 1 | 
                  use crate::components::{Movable,  | 
              |
| 1 | use crate::components::{Movable, Velocity}; | |
| 2 | use crate::game::MyGame; | |
| 2 | 3 | |
| 3 | 4 | use sdl2::keyboard as sdl; | 
| 5 | use specs::RunNow; | |
| 4 | 6 | |
| 5 | pub struct Move { | |
| 6 | pub keycode: sdl::Keycode, | |
| 7 | pub struct Move<'t> { | |
| 8 | keys: &'t std::collections::HashSet<sdl::Keycode>, | |
| 7 | 9 | } | 
| 8 | 10 | |
| 9 | 
                  impl<'a | 
              |
| 11 | impl<'a, 't> specs::System<'a> for Move<'t> { | |
| 10 | 12 | type SystemData = ( | 
| 11 | 13 | specs::ReadStorage<'a, Movable>, | 
| 12 | 
                          specs::WriteStorage<'a,  | 
              |
| 14 | specs::WriteStorage<'a, Velocity>, | |
| 13 | 15 | ); | 
| 14 | 16 | |
| 15 | 
                      fn run(&mut self, (movable, mut  | 
              |
| 17 | fn run(&mut self, (movable, mut velocity): Self::SystemData) { | |
| 16 | 18 | use specs::Join; | 
| 17 | 19 | |
| 18 | for (_, pos) in (&movable, &mut position).join() { | |
| 19 | match self.keycode { | |
| 20 | sdl::Keycode::W => pos.y -= 1.0, | |
| 21 | sdl::Keycode::A => pos.x -= 1.0, | |
| 22 | sdl::Keycode::S => pos.y += 1.0, | |
| 23 | sdl::Keycode::D => pos.x += 1.0, | |
| 24 | 
                           | 
              |
| 20 | for (_, vel) in (&movable, &mut velocity).join() { | |
| 21 | vel.dx = 0.0; | |
| 22 | vel.dy = 0.0; | |
| 23 | ||
| 24 | if self.keys.contains(&sdl::Keycode::W) { | |
| 25 | vel.dy -= 2.0; | |
| 26 | } | |
| 27 | if self.keys.contains(&sdl::Keycode::A) { | |
| 28 | vel.dx -= 2.0; | |
| 29 | } | |
| 30 | if self.keys.contains(&sdl::Keycode::S) { | |
| 31 | vel.dy += 2.0; | |
| 32 | } | |
| 33 | if self.keys.contains(&sdl::Keycode::D) { | |
| 34 | vel.dx += 2.0; | |
| 25 | 35 | } | 
| 26 | 36 | } | 
| 27 | 37 | } | 
| 28 | 38 | } | 
| 39 | ||
| 40 | ||
| 41 | pub fn systems(game: &mut MyGame) { | |
| 42 | Move { keys: &game.keys }.run_now(&game.world.res); | |
| 43 | } | 
| 1 | use crate::components::{Velocity, Position}; | |
| 2 | use crate::game::MyGame; | |
| 3 | ||
| 4 | use specs::RunNow; | |
| 5 | ||
| 6 | struct Physics; | |
| 7 | ||
| 8 | impl <'a> specs::System<'a> for Physics { | |
| 9 | type SystemData = ( | |
| 10 | specs::ReadStorage<'a, Velocity>, | |
| 11 | specs::WriteStorage<'a, Position>, | |
| 12 | ); | |
| 13 | ||
| 14 | fn run(&mut self, (velocity, mut position): Self::SystemData) { | |
| 15 | use specs::Join; | |
| 16 | ||
| 17 | for (vel, pos) in (&velocity, &mut position).join() { | |
| 18 | pos.x += vel.dx; | |
| 19 | pos.y += vel.dy; | |
| 20 | } | |
| 21 | } | |
| 22 | } | |
| 23 | ||
| 24 | ||
| 25 | pub fn systems(game: &mut MyGame) { | |
| 26 | Physics.run_now(&game.world.res); | |
| 27 | } |