diff --git a/assets/thumbnails/full-2-walls.png b/assets/thumbnails/full-2-walls-corner.png similarity index 100% rename from assets/thumbnails/full-2-walls.png rename to assets/thumbnails/full-2-walls-corner.png diff --git a/assets/thumbnails/full-2-walls-hallway.png b/assets/thumbnails/full-2-walls-hallway.png new file mode 100644 index 0000000..f0c34d0 Binary files /dev/null and b/assets/thumbnails/full-2-walls-hallway.png differ diff --git a/assets/tiles/full-2-walls.png b/assets/tiles/full-2-walls-corner.png similarity index 100% rename from assets/tiles/full-2-walls.png rename to assets/tiles/full-2-walls-corner.png diff --git a/assets/tiles/full-2-walls-hallway.png b/assets/tiles/full-2-walls-hallway.png new file mode 100644 index 0000000..79f0143 Binary files /dev/null and b/assets/tiles/full-2-walls-hallway.png differ diff --git a/src/assets.rs b/src/assets.rs index c2f780a..d2fe57b 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -33,7 +33,8 @@ impl AssetLibrary { "corner-sw-3-walls", "full-0-walls", "full-1-wall", - "full-2-walls", + "full-2-walls-corner", + "full-2-walls-hallway", "full-3-walls", "full-4-walls", ]; diff --git a/src/card.rs b/src/card.rs index 354292a..048a87d 100644 --- a/src/card.rs +++ b/src/card.rs @@ -14,6 +14,25 @@ pub enum Cell { Filled, } +#[derive(Clone, Copy, Debug)] +pub struct Walls { + pub north: bool, + pub east: bool, + pub south: bool, + pub west: bool, +} + +impl Walls { + pub fn new(north: bool, east: bool, south: bool, west: bool) -> Self { + Self { + north, + east, + south, + west, + } + } +} + #[derive(Clone, Copy, Debug)] pub enum CutLine { VertLeft, @@ -51,15 +70,15 @@ pub enum RotationDir { /// *or may not* be valid, yet. #[derive(Clone, Copy, Component, Debug, Default, PartialEq)] pub struct Card { - cells: [Cell; 9], - nw: bool, - n: bool, - ne: bool, - w: bool, - e: bool, - sw: bool, - s: bool, - se: bool, + pub cells: [Cell; 9], + pub nw: bool, + pub n: bool, + pub ne: bool, + pub w: bool, + pub e: bool, + pub sw: bool, + pub s: bool, + pub se: bool, } impl Card { diff --git a/src/game/map.rs b/src/game/map.rs index beb850e..26b9a14 100644 --- a/src/game/map.rs +++ b/src/game/map.rs @@ -2,6 +2,7 @@ use bevy::prelude::*; use bevy_ecs_tilemap::prelude::*; use crate::assets::AssetLibrary; +use crate::card::{Card, Cell, Walls}; pub fn setup_test_tilemap(mut commands: Commands, assets: Res) { let tilemap_entity = commands.spawn_empty().id(); @@ -10,57 +11,29 @@ pub fn setup_test_tilemap(mut commands: Commands, assets: Res) { let map_size = TilemapSize { x: 9, y: 9 }; let mut tile_storage = TileStorage::empty(map_size); - vec![ - ( - (0, 0), - assets.get_index("corner-sw-1-wall").unwrap(), - TileFlip::default(), - ), - ( - (1, 0), - 17, - TileFlip { - y: true, - ..Default::default() - }, - ), - ((2, 0), 8, TileFlip::default()), - ( - (0, 1), - 17, - TileFlip { - d: true, - ..Default::default() - }, - ), - ((1, 1), 16, TileFlip::default()), - ( - (2, 1), - 17, - TileFlip { - x: true, - d: true, - ..Default::default() - }, - ), - ((0, 2), 4, TileFlip::default()), - ((1, 2), 17, TileFlip::default()), - ((2, 2), 0, TileFlip::default()), - ] - .iter() - .for_each(|((x, y), texture_index, flip)| { - let position = TilePos { x: *x, y: *y }; - let tile_entity = commands - .spawn(TileBundle { - position, - tilemap_id, - texture_index: TileTextureIndex(*texture_index), - flip: *flip, - ..Default::default() - }) - .id(); - tile_storage.set(&position, tile_entity); - }); + let card = Card { + cells: [ + Cell::NW, + Cell::Filled, + Cell::NE, + Cell::Filled, + Cell::Filled, + Cell::Filled, + Cell::SW, + Cell::Filled, + Cell::SE, + ], + ..Default::default() + }; + + add_card_to_tilemap( + &card, + &assets, + TilePos { x: 0, y: 2 }, + tilemap_id, + &mut commands, + &mut tile_storage, + ); let tile_size = TilemapTileSize { x: 48.0, y: 48.0 }; let grid_size = tile_size.into(); @@ -83,3 +56,384 @@ pub fn setup_test_tilemap(mut commands: Commands, assets: Res) { ..Default::default() }); } + +/// Returns a cell description for a tilemap, including the texture index and a flip configuration +fn get_cell_description( + cell: &Cell, + walls: &Walls, + assets: &AssetLibrary, +) -> Option<(u32, TileFlip)> { + // Filter allowed walls + let walls = match cell { + Cell::NW => Walls { + north: false, + east: walls.east, + south: walls.south, + west: false, + }, + Cell::NE => Walls { + north: false, + east: false, + south: walls.south, + west: walls.west, + }, + Cell::SE => Walls { + north: walls.north, + east: false, + south: false, + west: walls.west, + }, + Cell::SW => Walls { + north: walls.north, + east: walls.east, + south: false, + west: false, + }, + _ => *walls, + }; + + let wall_count = (if walls.north { 1 } else { 0 }) + + (if walls.east { 1 } else { 0 }) + + (if walls.south { 1 } else { 0 }) + + (if walls.west { 1 } else { 0 }); + + match (cell, wall_count) { + (Cell::Empty, _) => None, + (Cell::NW, 0) => Some(( + assets.get_index("corner-nw-1-wall").unwrap(), + TileFlip::default(), + )), + (Cell::NW, 1) => { + if walls.east { + Some(( + assets.get_index("corner-nw-2-walls-east").unwrap(), + TileFlip::default(), + )) + } else if walls.south { + Some(( + assets.get_index("corner-nw-2-walls-south").unwrap(), + TileFlip::default(), + )) + } else { + unreachable!() + } + } + (Cell::NW, 2) => Some(( + assets.get_index("corner-nw-3-walls").unwrap(), + TileFlip::default(), + )), + (Cell::NE, 0) => Some(( + assets.get_index("corner-ne-1-wall").unwrap(), + TileFlip::default(), + )), + (Cell::NE, 1) => { + if walls.west { + Some(( + assets.get_index("corner-ne-2-walls-west").unwrap(), + TileFlip::default(), + )) + } else if walls.south { + Some(( + assets.get_index("corner-ne-2-walls-south").unwrap(), + TileFlip::default(), + )) + } else { + unreachable!() + } + } + (Cell::NE, 2) => Some(( + assets.get_index("corner-ne-3-walls").unwrap(), + TileFlip::default(), + )), + (Cell::SE, 0) => Some(( + assets.get_index("corner-se-1-wall").unwrap(), + TileFlip::default(), + )), + (Cell::SE, 1) => { + if walls.west { + Some(( + assets.get_index("corner-se-2-walls-west").unwrap(), + TileFlip::default(), + )) + } else if walls.north { + Some(( + assets.get_index("corner-se-2-walls-north").unwrap(), + TileFlip::default(), + )) + } else { + unreachable!() + } + } + (Cell::SE, 2) => Some(( + assets.get_index("corner-se-3-walls").unwrap(), + TileFlip::default(), + )), + (Cell::SW, 0) => Some(( + assets.get_index("corner-sw-1-wall").unwrap(), + TileFlip::default(), + )), + (Cell::SW, 1) => { + if walls.east { + Some(( + assets.get_index("corner-sw-2-walls-east").unwrap(), + TileFlip::default(), + )) + } else if walls.north { + Some(( + assets.get_index("corner-sw-2-walls-north").unwrap(), + TileFlip::default(), + )) + } else { + unreachable!() + } + } + (Cell::SW, 2) => Some(( + assets.get_index("corner-sw-3-walls").unwrap(), + TileFlip::default(), + )), + (Cell::Filled, 0) => Some(( + assets.get_index("full-0-walls").unwrap(), + TileFlip::default(), + )), + (Cell::Filled, 1) => { + if walls.north { + Some(( + assets.get_index("full-1-wall").unwrap(), + TileFlip::default(), + )) + } else if walls.east { + Some(( + assets.get_index("full-1-wall").unwrap(), + TileFlip { + x: true, + y: false, + d: true, + }, + )) + } else if walls.south { + Some(( + assets.get_index("full-1-wall").unwrap(), + TileFlip { + x: false, + y: true, + d: false, + }, + )) + } else { + // walls.west + Some(( + assets.get_index("full-1-wall").unwrap(), + TileFlip { + x: false, + y: false, + d: true, + }, + )) + } + } + (Cell::Filled, 2) => { + if walls.west && walls.north { + Some(( + assets.get_index("full-2-walls-corner").unwrap(), + TileFlip::default(), + )) + } else if walls.north && walls.east { + Some(( + assets.get_index("full-2-walls-corner").unwrap(), + TileFlip { + x: true, + y: false, + d: false, + }, + )) + } else if walls.east && walls.south { + Some(( + assets.get_index("full-2-walls-corner").unwrap(), + TileFlip { + x: true, + y: true, + d: false, + }, + )) + } else if walls.south && walls.west { + Some(( + assets.get_index("full-2-walls-corner").unwrap(), + TileFlip { + x: false, + y: true, + d: false, + }, + )) + } else if walls.north && walls.south { + Some(( + assets.get_index("full-2-walls-hallway").unwrap(), + TileFlip { + x: false, + y: false, + d: false, + }, + )) + } else if walls.east && walls.west { + Some(( + assets.get_index("full-2-walls-hallway").unwrap(), + TileFlip { + x: false, + y: false, + d: true, + }, + )) + } else { + unreachable!() + } + } + (Cell::Filled, 3) => { + if !walls.north { + Some(( + assets.get_index("full-3-walls").unwrap(), + TileFlip { + x: false, + y: true, + d: true, + }, + )) + } else if !walls.east { + Some(( + assets.get_index("full-3-walls").unwrap(), + TileFlip::default(), + )) + } else if !walls.south { + Some(( + assets.get_index("full-3-walls").unwrap(), + TileFlip { + x: false, + y: false, + d: true, + }, + )) + } else if walls.west { + Some(( + assets.get_index("full-3-walls").unwrap(), + TileFlip { + x: true, + y: false, + d: false, + }, + )) + } else { + unreachable!() + } + } + (Cell::Filled, 4) => Some(( + assets.get_index("full-4-walls").unwrap(), + TileFlip::default(), + )), + _ => unreachable!(), + } +} + +/// Returns an array of cell descriptions, starting from the top right tile and moving right to left, top to bottom +fn get_card_description(card: &Card, assets: &AssetLibrary) -> [Option<(u32, TileFlip)>; 9] { + let mut walls = [ + Walls::new(true, false, false, true), + Walls::new(true, false, false, false), + Walls::new(true, true, false, false), + Walls::new(false, false, false, true), + Walls::new(false, false, false, false), + Walls::new(false, true, false, false), + Walls::new(false, false, true, true), + Walls::new(false, false, true, false), + Walls::new(false, true, true, false), + ]; + + if card.cells[0] == Cell::Empty { + walls[1].west = true; + walls[3].north = true; + } + if card.cells[1] == Cell::Empty { + walls[0].east = true; + walls[2].west = true; + walls[4].north = true; + } + if card.cells[2] == Cell::Empty { + walls[1].east = true; + walls[5].north = true; + } + if card.cells[3] == Cell::Empty { + walls[0].south = true; + walls[4].west = true; + walls[6].north = true; + } + if card.cells[4] == Cell::Empty { + walls[1].south = true; + walls[3].east = true; + walls[5].west = true; + walls[7].north = true; + } + if card.cells[5] == Cell::Empty { + walls[2].south = true; + walls[4].east = true; + walls[8].north = true; + } + if card.cells[6] == Cell::Empty { + walls[7].west = true; + walls[3].south = true; + } + if card.cells[7] == Cell::Empty { + walls[6].east = true; + walls[8].west = true; + walls[4].south = true; + } + if card.cells[8] == Cell::Empty { + walls[7].east = true; + walls[5].south = true; + } + + card + .cells + .iter() + .zip(walls.iter()) + .map(|(cell, walls)| get_cell_description(cell, walls, assets)) + .collect::>() + .try_into() + .unwrap() +} + +fn add_card_to_tilemap( + card: &Card, + assets: &AssetLibrary, + top_left: TilePos, + tilemap_id: TilemapId, + commands: &mut Commands, + tile_storage: &mut TileStorage, +) { + get_card_description(card, assets) + .iter() + .enumerate() + .for_each(|(index, desc)| { + let dx = (index as u32) % 3; + let dy = (index as u32) / 3; + + let position = TilePos { + x: top_left.x + dx, + y: top_left.y - dy, + }; + + match desc { + Some((texture_index, flip)) => { + let tile_entity = commands + .spawn(TileBundle { + position, + tilemap_id, + texture_index: TileTextureIndex(*texture_index), + flip: *flip, + ..Default::default() + }) + .id(); + tile_storage.set(&position, tile_entity); + } + None => { + tile_storage.remove(&position); + } + }; + }); +} diff --git a/src/game/mod.rs b/src/game/mod.rs index abafc61..1c41c8b 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -1,6 +1,7 @@ use bevy::prelude::*; pub mod map; +pub mod player; /// Data component for info about the player's current set of cards. /// diff --git a/src/game/player.rs b/src/game/player.rs new file mode 100644 index 0000000..5c2db92 --- /dev/null +++ b/src/game/player.rs @@ -0,0 +1,28 @@ +use bevy::prelude::*; + +#[derive(Component)] +#[require(Transform)] +pub struct Player; + +pub fn spawn_player( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + let shape = Circle::new(12.0); + let mesh = meshes.add(shape); + + let color = Color::srgb(1., 0., 0.); + let material = materials.add(color); + + commands.spawn(( + Player, + Mesh2d(mesh), + MeshMaterial2d(material), + Transform::from_translation(Vec3 { + x: 72., + y: 72., + z: 1., + }), + )); +}