123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- #[macro_use]
- extern crate specs_derive;
- #[macro_use]
- extern crate specs_system_macro;
- use carpet::Coord;
- use ggez::GameError;
- use rand::Rng;
- use specs::prelude::*;
- #[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>,
- rooms: Vec<carpet::Rect>,
- }
- impl Map {
- fn new() -> Map {
- let mut rng = rand::thread_rng();
- let mut map = Map {
- tiles: carpet::Board::new_with_default(80, 50, TileType::Wall),
- rooms: Vec::new(),
- };
- const MAX_ROOMS: usize = 30;
- const MIN_SIZE: usize = 6;
- const MAX_SIZE: usize = 10;
- for _ in 0..MAX_ROOMS {
- let w = rng.gen_range(MIN_SIZE, MAX_SIZE);
- let h = rng.gen_range(MIN_SIZE, MAX_SIZE);
- let x = rng.gen_range(1, 80 - w);
- let y = rng.gen_range(1, 50 - h);
- let room = carpet::Rect::new([x, y], [w, h]);
- if map.rooms.iter().any(|r| r.overlaps(room)) {
- continue;
- }
- map.carve(room);
- if let Some(prev) = map.rooms.first() {
- let c1 = room.center();
- let c2 = prev.center();
- let join = if rng.gen() {
- carpet::Coord { x: c1.x, y: c2.y }
- } else {
- carpet::Coord { x: c2.x, y: c1.y }
- };
- map.carve(carpet::Rect::from_points(c1, join));
- map.carve(carpet::Rect::from_points(join, c2));
- }
- map.rooms.push(room);
- }
- map
- }
- fn carve(&mut self, rect: carpet::Rect) {
- let iter = self
- .tiles
- .window_iter_mut(rect)
- .expect(&format!("Rect {:?} of map bounds", rect));
- for (_, _, t) in iter {
- *t = TileType::Floor;
- }
- }
- fn passable(&self, (x, y): (usize, usize)) -> bool {
- Some(&TileType::Floor) == self.tiles.get(x, y)
- }
- }
- #[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: Coord,
- ) {
- 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: Coord,
- ) {
- 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::<Coord>();
- game.register::<Renderable>();
- game.register::<Motion>();
- game.register::<Player>();
- let map = Map::new();
- let player_start = map
- .rooms
- .first()
- .map(|r| r.center())
- .unwrap_or([40, 25].into());
- game.insert(map);
- game.create_entity()
- .with(player_start)
- .with(Player)
- .with(Renderable {
- glyph: carpet::CP437::from_char('@'),
- color: carpet::Color::Blue,
- })
- .build();
- {
- // set up all the keybindings
- use carpet::VirtualKeyCode::*;
- let none = carpet::KeyMods::NONE;
- game.on_key((W, none), |world| Motion::move_player(world, -1, 0));
- game.on_key((A, none), |world| Motion::move_player(world, 0, -1));
- game.on_key((S, none), |world| Motion::move_player(world, 1, 0));
- game.on_key((D, none), |world| Motion::move_player(world, 0, 1));
- }
- game.run_with_systems(|world| {
- Draw.run_now(&world);
- Move.run_now(&world);
- })
- }
|