Cleaning
This commit is contained in:
parent
7bab06b2b6
commit
a66e596db0
|
@ -43,8 +43,8 @@ fn main() {
|
|||
let x = ((x - left_panel_size.x as i32) / SPRITE_SIZE_I32) as usize;
|
||||
let y = ((y - top_panel_size.y as i32) / SPRITE_SIZE_I32) as usize;
|
||||
|
||||
if let Some(tile) = map.tile(y, x) {
|
||||
if tile == CollisionTile::empty() {
|
||||
if let Some(tile) = map.collision_tile(y, x) {
|
||||
if tile.is_empty() {
|
||||
map.set_tile(y, x, CollisionTile::full());
|
||||
} else {
|
||||
map.set_tile(y, x, CollisionTile::empty());
|
||||
|
|
|
@ -82,6 +82,16 @@ impl CollisionTile {
|
|||
from_bottom: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests whether a collision tile is full or not.
|
||||
pub fn is_full(self) -> bool {
|
||||
self.from_top && self.from_left && self.from_right && self.from_bottom
|
||||
}
|
||||
|
||||
/// Tests whether a collision tile is empty or not.
|
||||
pub fn is_empty(self) -> bool {
|
||||
!self.from_top && !self.from_left && !self.from_right && !self.from_bottom
|
||||
}
|
||||
}
|
||||
|
||||
/// This struct represents a renderable tile linking to its part in the tileset texture.
|
||||
|
@ -94,79 +104,53 @@ impl GraphicTile {
|
|||
/// Creates the correct graphic tile depending on the neighbours.
|
||||
///
|
||||
/// A none will be considered solid.
|
||||
pub fn from_neighbour_options(
|
||||
top_left: Option<CollisionTile>,
|
||||
top: Option<CollisionTile>,
|
||||
top_right: Option<CollisionTile>,
|
||||
right: Option<CollisionTile>,
|
||||
bottom_right: Option<CollisionTile>,
|
||||
bottom: Option<CollisionTile>,
|
||||
bottom_left: Option<CollisionTile>,
|
||||
left: Option<CollisionTile>,
|
||||
) -> GraphicTile {
|
||||
GraphicTile::from_neighbours(
|
||||
top_left.unwrap_or_else(CollisionTile::full),
|
||||
top.unwrap_or_else(CollisionTile::full),
|
||||
top_right.unwrap_or_else(CollisionTile::full),
|
||||
right.unwrap_or_else(CollisionTile::full),
|
||||
bottom_right.unwrap_or_else(CollisionTile::full),
|
||||
bottom.unwrap_or_else(CollisionTile::full),
|
||||
bottom_left.unwrap_or_else(CollisionTile::full),
|
||||
left.unwrap_or_else(CollisionTile::full),
|
||||
)
|
||||
pub fn from_neighbour_options(tiles: &[Option<CollisionTile>; 8]) -> GraphicTile {
|
||||
GraphicTile::from_neighbours(&[
|
||||
tiles[0].unwrap_or_else(CollisionTile::full),
|
||||
tiles[1].unwrap_or_else(CollisionTile::full),
|
||||
tiles[2].unwrap_or_else(CollisionTile::full),
|
||||
tiles[3].unwrap_or_else(CollisionTile::full),
|
||||
tiles[4].unwrap_or_else(CollisionTile::full),
|
||||
tiles[5].unwrap_or_else(CollisionTile::full),
|
||||
tiles[6].unwrap_or_else(CollisionTile::full),
|
||||
tiles[7].unwrap_or_else(CollisionTile::full),
|
||||
])
|
||||
}
|
||||
|
||||
/// Creates the correct graphic tile depending on the neighbours.
|
||||
pub fn from_neighbours(
|
||||
top_left: CollisionTile,
|
||||
top: CollisionTile,
|
||||
top_right: CollisionTile,
|
||||
right: CollisionTile,
|
||||
bottom_right: CollisionTile,
|
||||
bottom: CollisionTile,
|
||||
bottom_left: CollisionTile,
|
||||
left: CollisionTile,
|
||||
) -> GraphicTile {
|
||||
pub fn from_neighbours(tiles: &[CollisionTile; 8]) -> GraphicTile {
|
||||
|
||||
let mut byte = 0;
|
||||
|
||||
if top_left != CollisionTile::full() ||
|
||||
left != CollisionTile::full() ||
|
||||
top != CollisionTile::full() {
|
||||
if !tiles[7].is_full() || !tiles[0].is_full() || !tiles[1].is_full() {
|
||||
byte += 1;
|
||||
}
|
||||
|
||||
if top != CollisionTile::full() {
|
||||
if !tiles[1].is_full() {
|
||||
byte += 2;
|
||||
}
|
||||
|
||||
if top_right != CollisionTile::full() ||
|
||||
top != CollisionTile::full() ||
|
||||
right != CollisionTile::full() {
|
||||
if !tiles[1] .is_full() || !tiles[2].is_full() || !tiles[3].is_full() {
|
||||
byte += 4;
|
||||
}
|
||||
|
||||
if right != CollisionTile::full() {
|
||||
if !tiles[3] .is_full() {
|
||||
byte += 8;
|
||||
}
|
||||
|
||||
if bottom_right != CollisionTile::full() ||
|
||||
bottom != CollisionTile::full() ||
|
||||
right != CollisionTile::full() {
|
||||
if !tiles[3].is_full() || !tiles[4].is_full() || !tiles[5].is_full() {
|
||||
byte += 16;
|
||||
}
|
||||
|
||||
if bottom != CollisionTile::full() {
|
||||
if !tiles[5].is_full() {
|
||||
byte += 32;
|
||||
}
|
||||
|
||||
if bottom_left != CollisionTile::full() ||
|
||||
bottom != CollisionTile::full() ||
|
||||
left != CollisionTile::full() {
|
||||
if !tiles[5].is_full() || !tiles[6].is_full() || !tiles[7].is_full() {
|
||||
byte += 64;
|
||||
}
|
||||
|
||||
if left != CollisionTile::full() {
|
||||
if !tiles[7] .is_full() {
|
||||
byte += 128;
|
||||
}
|
||||
|
||||
|
@ -214,14 +198,34 @@ impl Drawable for PositionedTile {
|
|||
}
|
||||
}
|
||||
|
||||
/// The map represents the tiles contained in a level.
|
||||
/// The content of a map that needs to be saved.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct SaveMap {
|
||||
/// The entrance point of the character in the map.
|
||||
entrance: (usize, usize),
|
||||
|
||||
/// The collision tiles contained in the level.
|
||||
collision_tiles: Matrix<CollisionTile>,
|
||||
}
|
||||
|
||||
impl SaveMap {
|
||||
/// Creates a map from the save map.
|
||||
fn to_map(self) -> Map {
|
||||
Map::from_entrance_and_collision_tiles(self.entrance, self.collision_tiles)
|
||||
}
|
||||
}
|
||||
|
||||
/// The map represents the tiles contained in a level.
|
||||
#[derive(Clone)]
|
||||
pub struct Map {
|
||||
/// The entrace point of the character in the map.
|
||||
entrance: (usize, usize),
|
||||
|
||||
/// The tiles contained in the level.
|
||||
tiles: Matrix<(CollisionTile, GraphicTile)>,
|
||||
/// The collision tiles contained in the level.
|
||||
collision_tiles: Matrix<CollisionTile>,
|
||||
|
||||
/// The graphic tiles contained in the level.
|
||||
graphic_tiles: Matrix<GraphicTile>,
|
||||
}
|
||||
|
||||
impl Map {
|
||||
|
@ -237,21 +241,29 @@ impl Map {
|
|||
Map::from_collision_tiles(tiles)
|
||||
}
|
||||
|
||||
/// Creates a SaveMap from a map
|
||||
fn save_map(&self) -> SaveMap {
|
||||
SaveMap {
|
||||
entrance: self.entrance,
|
||||
collision_tiles: self.collision_tiles.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes the map into a binary format.
|
||||
pub fn encode(&self) -> Result<Vec<u8>> {
|
||||
serialize(&self).map_err(Error::Encoding)
|
||||
serialize(&self.save_map()).map_err(Error::Encoding)
|
||||
}
|
||||
|
||||
/// Decodes a map from bytes.
|
||||
pub fn decode(content: &[u8]) -> Result<Map> {
|
||||
deserialize(content).map_err(Error::Decoding)
|
||||
deserialize(content).map(SaveMap::to_map).map_err(Error::Decoding)
|
||||
}
|
||||
|
||||
/// Saves the map to a file.
|
||||
pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||
let file = File::create(path.as_ref()).map_err(Error::Save)?;
|
||||
let mut writer = BufWriter::new(file);
|
||||
serialize_into(&mut writer, &self).map_err(Error::Encoding)?;
|
||||
serialize_into(&mut writer, &self.save_map()).map_err(Error::Encoding)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -259,85 +271,83 @@ impl Map {
|
|||
pub fn load<P: AsRef<Path>>(path: P) -> Result<Map> {
|
||||
let file = File::open(path.as_ref()).map_err(Error::Load)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
Ok(deserialize_from(&mut reader).map_err(Error::Decoding)?)
|
||||
Ok(deserialize_from(&mut reader).map(SaveMap::to_map).map_err(Error::Decoding)?)
|
||||
}
|
||||
|
||||
/// Creates a map from its entrance and collision tiles.
|
||||
pub fn from_entrance_and_collision_tiles(e: (usize, usize), t: Matrix<CollisionTile>) -> Map {
|
||||
let rows = t.rows();
|
||||
let cols = t.cols();
|
||||
|
||||
let graphic_tiles = Matrix::from_size(rows, cols, GraphicTile(None));
|
||||
|
||||
let mut map = Map {
|
||||
entrance: e,
|
||||
collision_tiles: t,
|
||||
graphic_tiles,
|
||||
};
|
||||
|
||||
for i in 0 .. rows {
|
||||
for j in 0 .. cols {
|
||||
map.graphic_tiles[(i, j)] = map.graphic_tile(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
/// Creates a map from its tiles.
|
||||
pub fn from_collision_tiles(tiles: Matrix<CollisionTile>) -> Map {
|
||||
let rows = tiles.rows();
|
||||
let cols = tiles.cols();
|
||||
|
||||
let mut matrix =
|
||||
Matrix::from_size(rows, cols, (CollisionTile::empty(), GraphicTile(None)));
|
||||
|
||||
for i in 0..rows {
|
||||
for j in 0..cols {
|
||||
let graphic = if tiles[(i, j)] == CollisionTile::full() {
|
||||
// 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 - 1) as usize, (j - 1) as usize)).cloned(),
|
||||
tiles.get(((i ) as usize, (j - 1) as usize)).cloned(),
|
||||
tiles.get(((i + 1) as usize, (j - 1) as usize)).cloned(),
|
||||
tiles.get(((i + 1) as usize, (j ) as usize)).cloned(),
|
||||
tiles.get(((i + 1) as usize, (j + 1) as usize)).cloned(),
|
||||
tiles.get(((i ) as usize, (j + 1) as usize)).cloned(),
|
||||
tiles.get(((i - 1) as usize, (j + 1) as usize)).cloned(),
|
||||
tiles.get(((i - 1) as usize, (j ) as usize)).cloned(),
|
||||
)
|
||||
} else {
|
||||
GraphicTile(None)
|
||||
};
|
||||
|
||||
matrix[(i, j)] = (tiles[(i, j)], graphic);
|
||||
}
|
||||
pub fn from_collision_tiles(collision_tiles: Matrix<CollisionTile>) -> Map {
|
||||
let entrance = Map::find_entrance(&collision_tiles);
|
||||
Map::from_entrance_and_collision_tiles(entrance, collision_tiles)
|
||||
}
|
||||
|
||||
Map {
|
||||
entrance: Map::find_entrance(&matrix),
|
||||
tiles: matrix,
|
||||
}
|
||||
/// Creates the neighbours of a tile.
|
||||
pub fn neighbours(&self, i: isize, j: isize) -> [Option<CollisionTile>; 8] {
|
||||
[
|
||||
self.collision_tiles.get_isize(i - 1, j - 1).cloned(),
|
||||
self.collision_tiles.get_isize(i - 1, j ).cloned(),
|
||||
self.collision_tiles.get_isize(i - 1, j + 1).cloned(),
|
||||
self.collision_tiles.get_isize(i , j + 1).cloned(),
|
||||
self.collision_tiles.get_isize(i + 1, j + 1).cloned(),
|
||||
self.collision_tiles.get_isize(i + 1, j ).cloned(),
|
||||
self.collision_tiles.get_isize(i + 1, j - 1).cloned(),
|
||||
self.collision_tiles.get_isize(i , j - 1).cloned(),
|
||||
]
|
||||
}
|
||||
|
||||
/// Returns the graphic tile corresponding to the collision tiles.
|
||||
pub fn graphic_tile(&self, i: usize, j: usize) -> GraphicTile {
|
||||
if self.tiles[(i, j)].0 == CollisionTile::full() {
|
||||
GraphicTile::from_neighbour_options(
|
||||
self.tiles.get(((i - 1) as usize, (j - 1) as usize)).map(|x| x.0),
|
||||
self.tiles.get(((i - 1) as usize, (j ) as usize)).map(|x| x.0),
|
||||
self.tiles.get(((i - 1) as usize, (j + 1) as usize)).map(|x| x.0),
|
||||
self.tiles.get(((i ) as usize, (j + 1) as usize)).map(|x| x.0),
|
||||
self.tiles.get(((i + 1) as usize, (j + 1) as usize)).map(|x| x.0),
|
||||
self.tiles.get(((i + 1) as usize, (j ) as usize)).map(|x| x.0),
|
||||
self.tiles.get(((i + 1) as usize, (j - 1) as usize)).map(|x| x.0),
|
||||
self.tiles.get(((i ) as usize, (j - 1) as usize)).map(|x| x.0),
|
||||
)
|
||||
if self.collision_tiles[(i, j)].is_full() {
|
||||
GraphicTile::from_neighbour_options(&self.neighbours(i as isize, j as isize))
|
||||
} else {
|
||||
GraphicTile(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a tile of the map.
|
||||
pub fn tile(&self, i: usize, j: usize) -> Option<CollisionTile> {
|
||||
self.tiles.get((i, j)).map(|x| x.0)
|
||||
pub fn collision_tile(&self, i: usize, j: usize) -> Option<CollisionTile> {
|
||||
self.collision_tiles.get((i, j)).cloned()
|
||||
}
|
||||
|
||||
/// Changes a tile of the map.
|
||||
pub fn set_tile(&mut self, i: usize, j: usize, tile: CollisionTile) {
|
||||
self.tiles[(i, j)] = (tile, GraphicTile(None));
|
||||
// Change the collision tile
|
||||
self.collision_tiles[(i, j)] = tile;
|
||||
|
||||
// Refresh the current graphic tile and their neighbours
|
||||
for i in (i - 1) ..= (i + 1) {
|
||||
for j in (j - 1) ..= (j + 1) {
|
||||
if self.tiles.get((i, j)).is_some() {
|
||||
self.tiles[(i, j)].1 = self.graphic_tile(i, j);
|
||||
let new_tile = self.graphic_tile(i, j);
|
||||
if let Some(tile) = self.graphic_tiles.get_mut((i, j)) {
|
||||
*tile = new_tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds a possible entrance.
|
||||
pub fn find_entrance(tiles: &Matrix<(CollisionTile, GraphicTile)>) -> (usize, usize) {
|
||||
pub fn find_entrance(tiles: &Matrix<CollisionTile>) -> (usize, usize) {
|
||||
(tiles.rows() - 5, 1)
|
||||
}
|
||||
|
||||
|
@ -349,20 +359,20 @@ impl Map {
|
|||
/// Returns an iterator to the positioned tiles.
|
||||
pub fn at(&self, row: usize, col: usize) -> PositionedTile {
|
||||
PositionedTile {
|
||||
collision: self.tiles[(row, col)].0,
|
||||
graphic: self.tiles[(row, col)].1,
|
||||
collision: self.collision_tiles[(row, col)],
|
||||
graphic: self.graphic_tiles[(row, col)],
|
||||
position: (col as f32 * SPRITE_SIZE_F32, row as f32 * SPRITE_SIZE_F32),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of rows of the map.
|
||||
pub fn rows(&self) -> usize {
|
||||
self.tiles.rows()
|
||||
self.collision_tiles.rows()
|
||||
}
|
||||
|
||||
/// Returns the number of columns of the map.
|
||||
pub fn cols(&self) -> usize {
|
||||
self.tiles.cols()
|
||||
self.collision_tiles.cols()
|
||||
}
|
||||
|
||||
/// Checks whether the bounding box collides with elements of the map.
|
||||
|
@ -376,8 +386,8 @@ impl Map {
|
|||
|
||||
let mut damage = Damage::None;
|
||||
|
||||
let cols = self.tiles.cols() - 1;
|
||||
let rows = self.tiles.rows() - 1;
|
||||
let cols = self.collision_tiles.cols() - 1;
|
||||
let rows = self.collision_tiles.rows() - 1;
|
||||
|
||||
let min_col = clamp(new.left / SPRITE_SIZE_F32, 0.0, cols as f32) as usize;
|
||||
let min_row = clamp(new.top / SPRITE_SIZE_F32, 0.0, rows as f32) as usize;
|
||||
|
@ -401,7 +411,7 @@ impl Map {
|
|||
}
|
||||
|
||||
// Collisions between feet and ground
|
||||
if self.tiles[(row, col)].0.from_top
|
||||
if self.collision_tiles[(row, col)].from_top
|
||||
&& old.top + old.height <= tile_top
|
||||
&& new.top + new.height >= tile_top
|
||||
{
|
||||
|
@ -414,7 +424,7 @@ impl Map {
|
|||
}
|
||||
|
||||
// Collisions between right and right wall
|
||||
if self.tiles[(row, col)].0.from_left
|
||||
if self.collision_tiles[(row, col)].from_left
|
||||
&& old.left + old.width <= tile_left
|
||||
&& new.left + new.width >= tile_left
|
||||
{
|
||||
|
@ -427,7 +437,7 @@ impl Map {
|
|||
}
|
||||
|
||||
// Collisions between left and left wall
|
||||
if self.tiles[(row, col)].0.from_right
|
||||
if self.collision_tiles[(row, col)].from_right
|
||||
&& old.left >= tile_left + SPRITE_SIZE_F32
|
||||
&& new.left <= tile_left + SPRITE_SIZE_F32
|
||||
{
|
||||
|
@ -440,7 +450,7 @@ impl Map {
|
|||
}
|
||||
|
||||
// Collisions between head and roof
|
||||
if self.tiles[(row, col)].0.from_bottom
|
||||
if self.collision_tiles[(row, col)].from_bottom
|
||||
&& old.top >= tile_top + SPRITE_SIZE_F32
|
||||
&& new.top <= tile_top + SPRITE_SIZE_F32
|
||||
{
|
||||
|
@ -463,8 +473,8 @@ impl Map {
|
|||
}
|
||||
|
||||
// Collision between the player and the void
|
||||
if new.top > self.tiles.rows() as f32 * SPRITE_SIZE_F32 {
|
||||
new.top = self.tiles.rows() as f32 * SPRITE_SIZE_F32;
|
||||
if new.top > self.collision_tiles.rows() as f32 * SPRITE_SIZE_F32 {
|
||||
new.top = self.collision_tiles.rows() as f32 * SPRITE_SIZE_F32;
|
||||
collision_y = true;
|
||||
damage = Damage::Death;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ pub fn duration_as_f32(duration: &Duration) -> f32 {
|
|||
}
|
||||
|
||||
/// A generic matrix type, useful for levels.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Matrix<T> {
|
||||
/// The number of rows of the matrix.
|
||||
rows: usize,
|
||||
|
@ -77,6 +77,25 @@ impl<T> Matrix<T> {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Returns the tile if any, none otherwise.
|
||||
pub fn get_isize(&self, row: isize, col: isize) -> Option<&T> {
|
||||
if row >= 0 && col >= 0 && (row as usize) < self.rows && (col as usize) < self.cols {
|
||||
Some(&self[(row as usize, col as usize)])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the tile if any.
|
||||
pub fn get_mut(&mut self, (row, col): (usize, usize)) -> Option<&mut T> {
|
||||
if row < self.rows && col < self.cols {
|
||||
Some(&mut self[(row, col)])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Index<(usize, usize)> for Matrix<T> {
|
||||
|
|
Loading…
Reference in New Issue