#[macro_use] extern crate specs_derive; #[macro_use] extern crate specs_system_macro; use ggez::GameError; use specs::prelude::*; use rand::Rng; #[derive(PartialEq, Clone, Copy, Debug)] pub enum TileType { Wall, Floor, } impl TileType { fn glyph(&self) -> carpet::CP437 { match self { TileType::Wall => carpet::CP437::from_char('#'), TileType::Floor => carpet::CP437::from_u8(0), } } } pub struct Map { tiles: carpet::Board, } impl Map { fn new() -> Map { let mut rng = rand::thread_rng(); let tiles = carpet::Board::new_from(80, 50, |x, y| { if x == 0 || x == 79 || y == 0 || y == 49 { TileType::Wall } else if rng.gen::() % 8 == 0 { TileType::Wall } else { TileType::Floor } }); Map { tiles } } fn passable(&self, (x, y): (usize, usize)) -> bool { Some(&TileType::Floor) == self.tiles.get(x, y) } } #[derive(Component)] pub struct Pos { x: usize, y: usize, } #[derive(Component)] pub struct Renderable { glyph: carpet::CP437, color: carpet::Color, } #[derive(Component)] pub struct Player; impl Player { fn get_entity(world: &mut specs::World) -> Entity { let storage = (&world.read_component::(), &world.entities()); storage.join().next().expect("No entities tagged as Player").1 } } #[derive(Component)] pub struct Motion { down: i8, right: i8, } impl Motion { fn move_player(world: &mut specs::World, down: i8, right: i8) { let player = Player::get_entity(world); world.write_component::().insert(player, Motion { down, right }).unwrap(); } } system_impl! { Draw( resource mut game_board: carpet::GameBoard, resource map: Map, renderable: Renderable, pos: Pos, ) { game_board.clear(); for (x, y, t) in map.tiles.iter() { game_board.set([x, y], t.glyph()); } for (p, r) in (&pos, &renderable).join() { game_board.set_with_color([p.x, p.y], r.glyph, r.color); } } } system! { Move ( resource map: Map, mut motion: Motion, mut pos: Pos, ) { let tgt_x = (pos.x as i8 + motion.right) as usize; let tgt_y = (pos.y as i8 + motion.down) as usize; if map.passable((tgt_x, tgt_y)) { pos.x = tgt_x; pos.y = tgt_y; } } finally { motion.clear(); } } fn main() -> Result<(), GameError> { let mut game: carpet::Game = carpet::GameBuilder::new() .name("game") .author("me") .resource_path({ let base = std::env::var("CARGO_MANIFEST_DIR").unwrap(); let mut path = std::path::PathBuf::from(base); path.pop(); path.push("resources"); path }) .tileset("/haberdash.gif", [12, 12]) .map_size(80, 50) .build()?; game.register::(); game.register::(); game.register::(); game.register::(); game.insert(Map::new()); game.create_entity() .with(Pos { x: 40, y: 25 }) .with(Player) .with(Renderable { glyph: carpet::CP437::from_char('A'), color: carpet::Color::Blue, }) .build(); game.on_key((carpet::VirtualKeyCode::W, carpet::KeyMods::NONE), |world| { Motion::move_player(world, -1, 0); }); game.on_key((carpet::VirtualKeyCode::A, carpet::KeyMods::NONE), |world| { Motion::move_player(world, 0, -1); }); game.on_key((carpet::VirtualKeyCode::S, carpet::KeyMods::NONE), |world| { Motion::move_player(world, 1, 0); }); game.on_key((carpet::VirtualKeyCode::D, carpet::KeyMods::NONE), |world| { Motion::move_player(world, 0, 1); }); game.run_with_systems(|world| { Draw.run_now(&world); Move.run_now(&world); }) }