diff --git a/src/engine/character/mod.rs b/src/engine/character/mod.rs index 2ec938b..de850f3 100644 --- a/src/engine/character/mod.rs +++ b/src/engine/character/mod.rs @@ -8,6 +8,7 @@ use sfml::window::Event; use sfml::window::Key; use sfml::graphics::{ IntRect, + FloatRect, View, }; @@ -146,6 +147,10 @@ impl Character { View::new(self.position, Vector2::new(24.0 * 16.0, 24.0 * 9.0)) } + /// Returns the collision bounding box of the character. + pub fn bbox(&self) -> FloatRect { + FloatRect::new(self.position.x, self.position.y, 32.0, 32.0) + } } impl Updatable for Character { @@ -229,8 +234,4 @@ impl Drawable for Character { fn position(&self) -> Vector2 { self.position } - - fn origin(&self) -> Vector2 { - Vector2::new(16.0, 16.0) - } } diff --git a/src/engine/map/mod.rs b/src/engine/map/mod.rs index dc6ae77..d98be1d 100644 --- a/src/engine/map/mod.rs +++ b/src/engine/map/mod.rs @@ -1,10 +1,22 @@ use sfml::system::Vector2; -use sfml::graphics::IntRect; +use sfml::graphics::{ + IntRect, + FloatRect +}; use engine::texture::Texture; use engine::renderer::Drawable; use engine::math::Matrix; +/// This enum represents if the collision happens on the X axis or the Y axis. +pub enum CollisionAxis { + /// The X axis. + X, + + /// The Y axis. + Y, +} + /// This struct represents the different sides from which a collision can occur. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct CollisionTile { @@ -234,10 +246,6 @@ impl Drawable for PositionedTile { fn position(&self) -> Vector2 { self.position.into() } - - fn origin(&self) -> Vector2 { - Vector2::new(0.0, 0.0) - } } /// The map represents the tiles contained in a level. @@ -351,10 +359,48 @@ impl Map { self.tiles.cols() } + /// Checks whether the bounding box collides with an element of the map + pub fn collides_bbox(&self, old: FloatRect, new: FloatRect) -> Option<(CollisionAxis, Vector2)> { + // Top left corner + if let Some((axis, collision)) = self.collides_point( + Vector2::new(old.left, old.top), + Vector2::new(new.left, new.top), + ) { + return Some((axis, collision)); + } + + // Top right corner + if let Some((axis, collision)) = self.collides_point( + Vector2::new(old.left + old.width, old.top), + Vector2::new(new.left + new.width, new.top), + ) { + return Some((axis, collision - Vector2::new(new.width, 0.0))); + } + + // Bottom left corner + if let Some((axis, collision)) = self.collides_point( + Vector2::new(old.left, old.top + old.height), + Vector2::new(new.left, new.top + new.height), + ) { + return Some((axis, collision - Vector2::new(0.0, new.height))); + } + + // Bottom right corner + if let Some((axis, collision)) = self.collides_point( + Vector2::new(old.left + old.width, old.top + old.height), + Vector2::new(new.left + new.width, new.top + new.height), + ) { + return Some((axis, collision - Vector2::new(new.width, new.height))); + } + + None + } + /// 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 { + pub fn collides_point(&self, old: Vector2, new: Vector2) + -> Option<(CollisionAxis, Vector2)> { let height = new.y - old.y; let mut y = (old.y / 16.0).ceil() * 16.0; @@ -372,7 +418,7 @@ impl Map { if let Some((tile, _)) = self.tiles.get((row, col)) { if tile.from_top { - return Some(y); + return Some((CollisionAxis::Y, Vector2::new(x, y))); } } diff --git a/src/engine/renderer/mod.rs b/src/engine/renderer/mod.rs index 9b040b2..eb383d7 100644 --- a/src/engine/renderer/mod.rs +++ b/src/engine/renderer/mod.rs @@ -32,9 +32,6 @@ pub trait Drawable { /// Returns the position on which the drawable should be drawn. fn position(&self) -> Vector2; - - /// Returns the origin of the sprite. - fn origin(&self) -> Vector2; } /// The game window. @@ -92,7 +89,6 @@ impl Renderer { use sfml::graphics::Transformable; sprite.set_position(drawable.position()); - sprite.set_origin(drawable.origin()); self.window.draw(&sprite); } diff --git a/src/engine/scene/mod.rs b/src/engine/scene/mod.rs index 19e2386..c8cfdf3 100644 --- a/src/engine/scene/mod.rs +++ b/src/engine/scene/mod.rs @@ -4,7 +4,10 @@ use sfml::window::Event; use sfml::graphics::View; use engine::character::Character; -use engine::map::Map; +use engine::map::{ + Map, + CollisionAxis +}; /// Contains everything needed to play. pub struct Scene { @@ -75,14 +78,21 @@ impl Scene { pub fn update(&mut self, duration: &Duration) { for c in &mut self.characters { - let old = c.position; + let old = c.bbox(); c.update(duration); - - if let Some(height) = self.map.collides(old, c.position) { - c.position.y = height; - c.speed.y = 0.0; - c.ground_collision(); + if let Some((axis, position)) = self.map.collides_bbox(old, c.bbox()) { + match axis { + CollisionAxis::X => { + c.speed.x = 0.0; + c.position.x = position.x; + }, + CollisionAxis::Y => { + c.speed.y = 0.0; + c.position.y = position.y; + c.ground_collision(); + }, + } } else { c.fall_off(); }