diff --git a/assets/textures/overworld-raw.png b/assets/textures/overworld-raw.png new file mode 100644 index 0000000..19a368b Binary files /dev/null and b/assets/textures/overworld-raw.png differ diff --git a/assets/textures/overworld.png b/assets/textures/overworld.png new file mode 100644 index 0000000..f27ff69 Binary files /dev/null and b/assets/textures/overworld.png differ diff --git a/src/engine/map/mod.rs b/src/engine/map/mod.rs new file mode 100644 index 0000000..7018f4a --- /dev/null +++ b/src/engine/map/mod.rs @@ -0,0 +1,128 @@ +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 + } +} + diff --git a/src/engine/math/mod.rs b/src/engine/math/mod.rs index b8ff2a3..29b2909 100644 --- a/src/engine/math/mod.rs +++ b/src/engine/math/mod.rs @@ -45,7 +45,7 @@ impl Matrix where T: Clone { impl Matrix { /// Converts an a pair corresponding to the row and columns into an integer. pub fn to_usize(&self, (row, col): (usize, usize)) -> usize { - self.cols * col + row + self.rows * col + row } /// Returns the number of rows. @@ -57,6 +57,15 @@ impl Matrix { pub fn cols(&self) -> usize { self.cols } + + /// Returns the tile if any, none otherwise. + pub fn get(&self, (row, col): (usize, usize)) -> Option<&T> { + if row < self.rows && col < self.cols { + Some(&self[(row, col)]) + } else { + None + } + } } impl Index<(usize, usize)> for Matrix { diff --git a/src/engine/mod.rs b/src/engine/mod.rs index bd3be80..0d760c1 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -19,3 +19,6 @@ pub mod renderer; /// This module contains everything related to physics. pub mod physics; + +/// This module contains the map structure. +pub mod map; diff --git a/src/engine/renderer/mod.rs b/src/engine/renderer/mod.rs index 058842a..ab213c8 100644 --- a/src/engine/renderer/mod.rs +++ b/src/engine/renderer/mod.rs @@ -93,6 +93,16 @@ impl Renderer { /// Draws a scene on the window. pub fn draw_scene(&mut self, scene: &Scene) { + let map = scene.map(); + let rows = map.rows(); + let cols = map.cols(); + + for i in 0 .. rows { + for j in 0 .. cols { + self.draw(&map.at(i, j)); + } + } + for c in scene.characters() { self.draw(c); } diff --git a/src/engine/scene/mod.rs b/src/engine/scene/mod.rs index e4e843a..c1aa726 100644 --- a/src/engine/scene/mod.rs +++ b/src/engine/scene/mod.rs @@ -3,6 +3,7 @@ use std::time::Duration; use sfml::window::Event; use engine::character::Character; +use engine::map::Map; /// Contains everything needed to play. pub struct Scene { @@ -10,6 +11,9 @@ pub struct Scene { /// The characters contained in the scene. characters: Vec, + /// The map of the scene. + map: Map, + } impl Scene { @@ -18,6 +22,7 @@ impl Scene { pub fn new() -> Scene { Scene { characters: vec![], + map: Map::new(30, 30), } } @@ -30,10 +35,12 @@ impl Scene { pub fn update(&mut self, duration: &Duration) { for c in &mut self.characters { + let old = c.position; c.update(duration); - if c.position.y > 500.0 { - c.position.y = 500.0; + + if let Some(height) = self.map.collides(old, c.position) { + c.position.y = height; c.speed.y = 0.0; c.ground_collision(); } @@ -52,6 +59,11 @@ impl Scene { &self.characters } + /// Returns a reference to the map. + pub fn map(&self) -> &Map { + &self.map + } + } /// Trait that needs to be implemented for everything that can be updatable. diff --git a/src/engine/texture/mod.rs b/src/engine/texture/mod.rs index 6ea7057..3d63099 100644 --- a/src/engine/texture/mod.rs +++ b/src/engine/texture/mod.rs @@ -58,6 +58,7 @@ macro_rules! make_textures { make_textures!( Mario, mario, make_mario_texture, "../../../assets/textures/mario.png", + Overworld, overworld, make_overworld_texture, "../../../assets/textures/overworld.png", ); impl TextureManager {