use sfml::system::Vector2; use sfml::graphics::IntRect; use engine::texture::Texture; 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 { /// A tile that contains nothing. Empty, /// A solid 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), } } } /// A tile and its position. pub struct PositionedTile { /// The tile of the positioned tile. pub tile: Tile, /// The position of the positioned tile. pub position: (f32, f32), } impl Drawable for PositionedTile { fn texture(&self) -> Texture { Texture::Overworld } fn texture_rect(&self) -> IntRect { let offset = self.tile.offset(); IntRect::new(offset.0, offset.1, 16, 16) } fn position(&self) -> Vector2 { self.position.into() } } /// The map represents the tiles contained in a level. pub struct Map { /// The tiles contained in the level. tiles: Matrix, } 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 rows = tiles.rows(); for i in 0 .. tiles.cols() { tiles[(rows - 1, i)] = Tile::Solid; } tiles[(25, 12)] = Tile::Solid; tiles[(25, 13)] = Tile::Solid; tiles[(25, 14)] = Tile::Solid; tiles[(25, 15)] = Tile::Solid; Map { tiles: tiles, } } /// Returns an iterator to the positioned tiles. pub fn at(&self, row: usize, col: usize) -> PositionedTile { PositionedTile { tile: self.tiles[(row, col)], position: (col as f32 * 16.0, row as f32 * 16.0), } } /// Returns the number of rows of the map. pub fn rows(&self) -> usize { self.tiles.rows() } /// Returns the number of columns of the map. pub fn cols(&self) -> usize { self.tiles.cols() } /// Checks whether the vector (old, new) collides with an element of the map. /// /// Returns the height of the collision if any. pub fn collides(&self, old: Vector2, new: Vector2) -> Option { let height = new.y - old.y; let mut y = (old.y / 16.0).ceil() * 16.0; while y < new.y { let current_height = y - old.y; 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 let Some(Tile::Solid) = self.tiles.get((row, col)) { return Some(y); } y += 16.0; } None } }