|
@@ -0,0 +1,170 @@
|
|
|
+#[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<TileType>,
|
|
|
+}
|
|
|
+
|
|
|
+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::<u8>() % 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::<Player>(), &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::<Motion>().insert(player, Motion { down, right }).unwrap();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+system_impl! {
|
|
|
+ Draw(
|
|
|
+ resource mut game_board: carpet::GameBoard<carpet::CP437>,
|
|
|
+ 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::CP437> =
|
|
|
+ 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::<Pos>();
|
|
|
+ game.register::<Renderable>();
|
|
|
+ game.register::<Motion>();
|
|
|
+ game.register::<Player>();
|
|
|
+
|
|
|
+ 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);
|
|
|
+ })
|
|
|
+}
|