diff --git a/assets/levels/level1.txt b/assets/levels/level1.txt index b788cff..1b87f4a 100644 --- a/assets/levels/level1.txt +++ b/assets/levels/level1.txt @@ -1,10 +1,4 @@ -25 50 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +30 50 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 @@ -18,8 +12,20 @@ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 diff --git a/src/app/game.rs b/src/app/game.rs index 057a2f6..ece07e2 100644 --- a/src/app/game.rs +++ b/src/app/game.rs @@ -18,7 +18,7 @@ fn main() { let game_height = 600; let mut character = Character::with_controls(Controls::new()); - character.set_position((300.0, 200.0)); + character.set_position((10.0, 0.0)); let mut scene = Scene::new(); scene.add(character); diff --git a/src/engine/map/mod.rs b/src/engine/map/mod.rs index 829e1ce..351c72c 100644 --- a/src/engine/map/mod.rs +++ b/src/engine/map/mod.rs @@ -6,8 +6,8 @@ use engine::renderer::Drawable; use engine::math::Matrix; /// This struct represents the different type of tiles that can exist in our maps. -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum Tile { +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum CollisionTile { /// A tile that contains nothing. Empty, @@ -15,29 +15,188 @@ pub enum Tile { Solid } -impl Tile { - /// Returns the offset to the tile in the texture. - pub fn offset(&self) -> (i32, i32) { - match *self { - Tile::Empty => (0, 0), - Tile::Solid => (16, 0), - } - } - +impl CollisionTile { /// Creates a tile from a u8. - pub fn from_u8(id: u8) -> Option { + pub fn from_u8(id: u8) -> Option { match id { - 0 => Some(Tile::Empty), - 1 => Some(Tile::Solid), + 0 => Some(CollisionTile::Empty), + 1 => Some(CollisionTile::Solid), _ => None, } } } +/// This struct represents a renderable tile linking to its part in the tileset texture. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum GraphicTile { + /// There is nothing to draw. + Hidden, + + /// Top left corner of a solid tile. + TopLeft, + + /// Top of a solid tile. + Top, + + /// Top right corner of a solid tile. + TopRight, + + /// Left of a solid tile. + Left, + + /// Center of a solid tile. + Center, + + /// Right of a solid tile. + Right, + + /// Bottom left corner of a solid tile. + BottomLeft, + + /// Bottom of a solid tile. + Bottom, + + /// Bottom right corner of a solid tile. + BottomRight, +} + +impl GraphicTile { + + /// Checks if a graphic tile has a top border. + pub fn is_top(&self) -> bool { + match *self { + GraphicTile::TopLeft | GraphicTile::Top | GraphicTile::TopRight => true, + _ => false, + } + } + + /// Checks if a graphic tile has a left border. + pub fn is_left(&self) -> bool { + match *self { + GraphicTile::TopLeft | GraphicTile::Left | GraphicTile::BottomLeft => true, + _ => false, + } + } + + /// Checks if a graphic tile has a right border. + pub fn is_right(&self) -> bool { + match *self { + GraphicTile::TopRight | GraphicTile::Right | GraphicTile::BottomRight => true, + _ => false, + } + } + + /// Checks if a graphic tile has a bottom border. + pub fn is_bottom(&self) -> bool { + match *self { + GraphicTile::BottomLeft | GraphicTile::Bottom | GraphicTile::BottomRight => true, + _ => false, + } + } + + + + /// Creates a vec containing all the non hidden graphic tiles. + pub fn all() -> Vec { + vec![ + GraphicTile::TopLeft, + GraphicTile::Top, + GraphicTile::TopRight, + GraphicTile::Left, + GraphicTile::Center, + GraphicTile::Right, + GraphicTile::BottomLeft, + GraphicTile::Bottom, + GraphicTile::BottomRight, + ] + } + + /// Creates the correct graphic tile depending on the neighbours. + /// + /// A none will be considered solid. + pub fn from_neighbour_options( + top: Option, + left: Option, + right: Option, + bottom: Option) -> GraphicTile { + + GraphicTile::from_neighbours( + top.unwrap_or(CollisionTile::Solid), + left.unwrap_or(CollisionTile::Solid), + right.unwrap_or(CollisionTile::Solid), + bottom.unwrap_or(CollisionTile::Solid), + ) + } + + /// Creates the correct graphic tile depending on the neighbours. + pub fn from_neighbours( + top: CollisionTile, + left: CollisionTile, + right: CollisionTile, + bottom: CollisionTile) -> GraphicTile { + + let mut all = GraphicTile::all() + .into_iter() + .map(|x| (x, true)) + .collect::>(); + + for (ref mut tile, ref mut possible) in &mut all { + + if tile.is_top() == (top == CollisionTile::Solid) { + *possible = false; + } + + if tile.is_left() == (left == CollisionTile::Solid) { + *possible = false; + } + + if tile.is_right() == (right == CollisionTile::Solid) { + *possible = false; + } + + if tile.is_bottom() == (bottom == CollisionTile::Solid) { + *possible = false; + } + + } + + for (tile, possible) in all { + if possible { + return tile; + } + } + + panic!("Did not find a tile, implementation error"); + } + + /// Returns the offset to the corresponding graphic tile in the texture. + pub fn offset(&self) -> (i32, i32) { + let vertical = match *self { + GraphicTile::TopLeft | GraphicTile::Top | GraphicTile::TopRight => 0, + GraphicTile::Left | GraphicTile::Center | GraphicTile::Right => 16, + GraphicTile::BottomLeft | GraphicTile::Bottom | GraphicTile::BottomRight => 32, + _ => 0, + }; + + let horizontal = match *self { + GraphicTile::TopLeft | GraphicTile::Left | GraphicTile::BottomLeft => 0, + GraphicTile::Top | GraphicTile::Center | GraphicTile::Bottom => 16, + GraphicTile::TopRight | GraphicTile::Right | GraphicTile::BottomRight => 32, + _ => 0, + }; + + // (horizontal, vertical) + (vertical, horizontal) + } +} + /// A tile and its position. pub struct PositionedTile { - /// The tile of the positioned tile. - pub tile: Tile, + /// The graphic representation of the positioned tile. + pub graphic: GraphicTile, + + /// The collision representation of the positioned tile. + pub collision: CollisionTile, /// The position of the positioned tile. pub position: (f32, f32), @@ -49,7 +208,7 @@ impl Drawable for PositionedTile { } fn texture_rect(&self) -> IntRect { - let offset = self.tile.offset(); + let offset = self.graphic.offset(); IntRect::new(offset.0, offset.1, 16, 16) } @@ -62,7 +221,7 @@ impl Drawable for PositionedTile { pub struct Map { /// The tiles contained in the level. - tiles: Matrix, + tiles: Matrix<(CollisionTile, GraphicTile)>, } @@ -71,21 +230,19 @@ impl Map { /// Creates a map full of nothing, with a ground at the bottom. pub fn new(rows: usize, cols: usize) -> Map { - let mut tiles = Matrix::from_size(rows, cols, Tile::Empty); + let mut tiles = Matrix::from_size(rows, cols, CollisionTile::Empty); let rows = tiles.rows(); for i in 0 .. tiles.cols() { - tiles[(rows - 1, i)] = Tile::Solid; + tiles[(rows - 1, i)] = CollisionTile::Solid; } - tiles[(25, 12)] = Tile::Solid; - tiles[(25, 13)] = Tile::Solid; - tiles[(25, 14)] = Tile::Solid; - tiles[(25, 15)] = Tile::Solid; + tiles[(25, 12)] = CollisionTile::Solid; + tiles[(25, 13)] = CollisionTile::Solid; + tiles[(25, 14)] = CollisionTile::Solid; + tiles[(25, 15)] = CollisionTile::Solid; - Map { - tiles: tiles, - } + Map::from_collision_tiles(tiles) } @@ -99,23 +256,59 @@ impl Map { .map(|x| x.parse::().unwrap()) .collect::>(); - let mut tiles = Matrix::from_size(size[0], size[1], Tile::Empty); + let mut tiles = Matrix::from_size(size[0], size[1], CollisionTile::Empty); for (row, line) in split.iter().skip(1).enumerate() { for (col, tile) in line.split_whitespace().enumerate() { - tiles[(row, col)] = Tile::from_u8(tile.parse::().unwrap()).unwrap(); + tiles[(row, col)] = CollisionTile::from_u8(tile.parse::().unwrap()).unwrap(); } } - Ok(Map { - tiles: tiles, - }) + Ok(Map::from_collision_tiles(tiles)) + } + + /// Creates a map from its tiles. + pub fn from_collision_tiles(tiles: Matrix) -> Map { + let rows = tiles.rows(); + let cols = tiles.cols(); + + let mut matrix = Matrix::from_size(rows, cols, + (CollisionTile::Empty, GraphicTile::Hidden) + ); + + for i in 0 .. rows { + for j in 0 .. cols { + + let graphic = if tiles[(i, j)] == CollisionTile::Solid { + + // TODO This is uggly + // If there is an overflow, we should give None instead + let (i, j) = (i as isize, j as isize); + + GraphicTile::from_neighbour_options( + tiles.get(((i ) as usize, (j-1) as usize)).map(|x| *x), + tiles.get(((i-1) as usize, (j ) as usize)).map(|x| *x), + tiles.get(((i+1) as usize, (j ) as usize)).map(|x| *x), + tiles.get(((i ) as usize, (j+1) as usize)).map(|x| *x), + ) + } else { + GraphicTile::Hidden + }; + + matrix[(i, j)] = (tiles[(i, j)], graphic); + } + } + + Map { + tiles: matrix, + } } /// Returns an iterator to the positioned tiles. pub fn at(&self, row: usize, col: usize) -> PositionedTile { PositionedTile { - tile: self.tiles[(row, col)], + collision: self.tiles[(row, col)].0, + graphic: self.tiles[(row, col)].1, position: (col as f32 * 16.0, row as f32 * 16.0), } } @@ -144,11 +337,15 @@ impl Map { let x = old.x + (new.x - old.x) * current_height / height; // Find tile on x, y - let row = (y / 16.0) as usize + 2; - let col = (x / 16.0) as usize + 1; + if x > 0.0 && y > 0.0 { + + let row = (y / 16.0) as usize + 2; + let col = (x / 16.0) as usize + 1; + + if let Some((CollisionTile::Solid, _)) = self.tiles.get((row, col)) { + return Some(y); + } - if let Some(Tile::Solid) = self.tiles.get((row, col)) { - return Some(y); } y += 16.0; diff --git a/src/engine/renderer/mod.rs b/src/engine/renderer/mod.rs index 2291cc1..96a0ed6 100644 --- a/src/engine/renderer/mod.rs +++ b/src/engine/renderer/mod.rs @@ -19,7 +19,7 @@ use sfml::system::{ use engine::texture::{Texture, TextureManager}; use engine::scene::Scene; -use engine::map::Tile; +use engine::map::GraphicTile; /// Our custom drawable trait. pub trait Drawable { @@ -101,7 +101,7 @@ impl Renderer { for i in 0 .. rows { for j in 0 .. cols { let tile = map.at(i,j); - if tile.tile != Tile::Empty { + if tile.graphic != GraphicTile::Hidden { self.draw(&tile); } }