Something that compiles

This commit is contained in:
Thomas Forgione 2022-07-30 13:37:34 +02:00
parent 96f3b3f33c
commit 466760c6a7
7 changed files with 135 additions and 89 deletions

View File

@ -3,6 +3,7 @@
use crate::engine::vector::Vector; use crate::engine::vector::Vector;
/// This struct represents a bounding box. /// This struct represents a bounding box.
#[derive(Copy, Clone)]
pub struct Bbox { pub struct Bbox {
/// The position of the top right corner of the box. /// The position of the top right corner of the box.
pub position: Vector, pub position: Vector,

View File

@ -3,17 +3,13 @@
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use crate::engine::bbox::Bbox; use crate::engine::bbox::Bbox;
use crate::engine::controls::Controls;
use crate::engine::event::Keyboard;
use crate::engine::math::{clamp, duration_as_f64};
use crate::engine::physics; use crate::engine::physics;
use crate::engine::scene::Updatable; use crate::engine::scene::Updatable;
use crate::engine::vector::Vector; use crate::engine::vector::Vector;
use crate::engine::controls::Controls;
use crate::engine::math::{clamp, duration_as_f64, duration_as_frame};
// use crate::engine::physics;
// use crate::engine::renderer::Drawable;
// use crate::engine::scene::Updatable;
// use crate::engine::texture::Texture;
/// The different sides a character can face. /// The different sides a character can face.
pub enum Side { pub enum Side {
/// The character looks to the left. /// The character looks to the left.
@ -148,11 +144,11 @@ impl Character {
} }
impl Updatable for Character { impl Updatable for Character {
fn update(&mut self, duration: &Duration) { fn update(&mut self, duration: &Duration, keyboard: &Keyboard) {
let mut force = Vector::new(0.0, 0.0); let mut force = Vector::new(0.0, 0.0);
if let Some(ref controls) = self.controls { if let Some(ref controls) = self.controls {
force += controls.direction(); force += controls.direction(keyboard);
} }
if let Some(side) = Side::from_force(force) { if let Some(side) = Side::from_force(force) {
@ -182,7 +178,7 @@ impl Updatable for Character {
} }
let limit = match self.controls { let limit = match self.controls {
Some(controls) if controls.is_running() => physics::MAXIMUM_RUNNING_SPEED, Some(ref controls) if controls.is_running() => physics::MAXIMUM_RUNNING_SPEED,
_ => physics::MAXIMUM_WALKING_SPEED, _ => physics::MAXIMUM_WALKING_SPEED,
}; };

View File

@ -1,6 +1,6 @@
//! This module helps to deal with controls. //! This module helps to deal with controls.
use crate::engine::event::{Event, Key}; use crate::engine::event::{Event, Key, Keyboard};
use crate::engine::vector::Vector; use crate::engine::vector::Vector;
/// The different actions that a user can do. /// The different actions that a user can do.
@ -52,9 +52,9 @@ impl Controls {
} }
/// Returns the direction of the controls. /// Returns the direction of the controls.
pub fn direction(&self) -> Vector { pub fn direction(&self, keyboard: &Keyboard) -> Vector {
match self { match self {
Controls::Keyboard(ref map) => map.direction(), Controls::Keyboard(ref map) => map.direction(keyboard),
// Controls::Gamepad(ref map) => map.direction(), // Controls::Gamepad(ref map) => map.direction(),
} }
} }
@ -106,14 +106,14 @@ impl KeyboardMap {
} }
/// Returns the direction of the keys. /// Returns the direction of the keys.
pub fn direction(&self) -> Vector { pub fn direction(&self, keyboard: &Keyboard) -> Vector {
let mut ret = Vector::new(0.0, 0.0); let mut ret = Vector::new(0.0, 0.0);
const RIGHT: Vector = Vector { x: 1.0, y: 0.0 }; const RIGHT: Vector = Vector { x: 1.0, y: 0.0 };
if self.right_key.is_pressed() { if keyboard.is_key_pressed(self.right_key) {
ret += RIGHT; ret += RIGHT;
} }
if self.left_key.is_pressed() { if keyboard.is_key_pressed(self.left_key) {
ret -= RIGHT; ret -= RIGHT;
} }
ret ret

View File

@ -1 +0,0 @@
//! A module that makes it easier to deal with images.

View File

@ -4,14 +4,66 @@ use std::fs::File;
use std::io::Read; use std::io::Read;
use std::path::Path; use std::path::Path;
use sfml::graphics::{FloatRect, IntRect}; use crate::engine::bbox::Bbox;
use sfml::system::Vector2;
use crate::engine::character::Damage;
use crate::engine::math::{clamp, Matrix}; use crate::engine::math::{clamp, Matrix};
use crate::engine::renderer::Drawable; use crate::engine::texture::SPRITE_SIZE;
use crate::engine::texture::{byte_to_index, Texture, SPRITE_SIZE_F32, SPRITE_SIZE_I32}; use crate::engine::vector::Vector;
use crate::{Error, Result}; use crate::Result;
/// Converts the byte with bits corresponding to the neighbours to the offset on the generated
/// tileset.
pub fn byte_to_index(byte: u8) -> i32 {
match byte {
0 => 0,
1 => 1,
4 => 2,
5 => 3,
7 => 4,
16 => 5,
17 => 6,
20 => 7,
21 => 8,
23 => 9,
28 => 10,
29 => 11,
31 => 12,
64 => 13,
65 => 14,
68 => 15,
69 => 16,
71 => 17,
80 => 18,
81 => 19,
84 => 20,
85 => 21,
87 => 22,
92 => 23,
93 => 24,
95 => 25,
112 => 26,
113 => 27,
116 => 28,
117 => 29,
119 => 30,
124 => 31,
125 => 32,
127 => 33,
193 => 34,
197 => 35,
199 => 36,
209 => 37,
213 => 38,
215 => 39,
221 => 40,
223 => 41,
241 => 42,
245 => 43,
247 => 44,
253 => 45,
255 => 46,
_ => panic!("Incorrect byte {}", byte),
}
}
/// This enum represents if the collision happens on the X axis or the Y axis. /// This enum represents if the collision happens on the X axis or the Y axis.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -175,23 +227,23 @@ pub struct PositionedTile {
pub collision: CollisionTile, pub collision: CollisionTile,
/// The position of the positioned tile. /// The position of the positioned tile.
pub position: (f32, f32), pub position: Vector,
} }
impl Drawable for PositionedTile { // impl Drawable for PositionedTile {
fn texture(&self) -> Texture { // fn texture(&self) -> Texture {
Texture::Overworld // Texture::Overworld
} // }
//
fn texture_rect(&self) -> IntRect { // fn texture_rect(&self) -> Bbox {
let offset = self.graphic.offset(); // let offset = self.graphic.offset();
IntRect::new(offset.0, offset.1, SPRITE_SIZE_I32, SPRITE_SIZE_I32) // Bbox::new(offset.x, offset.x, SPRITE_SIZE, SPRITE_SIZE)
} // }
//
fn position(&self) -> Vector2<f32> { // fn position(&self) -> Vector {
self.position.into() // self.position
} // }
} // }
/// The map represents the tiles contained in a level. /// The map represents the tiles contained in a level.
#[derive(Clone)] #[derive(Clone)]
@ -219,14 +271,6 @@ impl Map {
Map::from_collision_tiles(tiles) Map::from_collision_tiles(tiles)
} }
/// Loads a map from a file.
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Map> {
let mut file = File::open(path.as_ref()).map_err(Error::Load)?;
let mut s = String::new();
file.read_to_string(&mut s).map_err(Error::Load)?;
Map::from_str(&s)
}
/// Loads a map from a string. /// Loads a map from a string.
pub fn from_str(text: &str) -> Result<Map> { pub fn from_str(text: &str) -> Result<Map> {
let split = text.split('\n').collect::<Vec<_>>(); let split = text.split('\n').collect::<Vec<_>>();
@ -390,7 +434,7 @@ impl Map {
PositionedTile { PositionedTile {
collision: self.collision_tiles[(row, col)], collision: self.collision_tiles[(row, col)],
graphic: self.graphic_tiles[(row, col)], graphic: self.graphic_tiles[(row, col)],
position: (col as f32 * SPRITE_SIZE_F32, row as f32 * SPRITE_SIZE_F32), position: Vector::new(col as f64 * SPRITE_SIZE, row as f64 * SPRITE_SIZE),
} }
} }
@ -407,21 +451,26 @@ impl Map {
/// Checks whether the bounding box collides with elements of the map. /// Checks whether the bounding box collides with elements of the map.
/// ///
/// Returns the new correct position. /// Returns the new correct position.
pub fn collides_bbox( pub fn collides_bbox(&self, old: Bbox, new: Bbox) -> Option<(CollisionAxis, Vector, bool)> {
&self, let mut death = false;
old: Bbox,
new: Bbox,
) -> Option<(CollisionAxis, Vector2<f32>, Damage)> {
let mut damage = Damage::None;
let cols = self.collision_tiles.cols() - 1; let cols = self.collision_tiles.cols() - 1;
let rows = self.collision_tiles.rows() - 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_col = clamp(new.position.x / SPRITE_SIZE, 0.0, cols as f64) as usize;
let min_row = clamp(new.top / SPRITE_SIZE_F32, 0.0, rows as f32) as usize; let min_row = clamp(new.position.y / SPRITE_SIZE, 0.0, rows as f64) as usize;
let max_col = clamp((new.left + new.width) / SPRITE_SIZE_F32, 0.0, cols as f32) as usize; let max_col = clamp(
let max_row = clamp((new.top + new.height) / SPRITE_SIZE_F32, 0.0, rows as f32) as usize; (new.position.x + new.size.x) / SPRITE_SIZE,
0.0,
cols as f64,
) as usize;
let max_row = clamp(
(new.position.y + new.size.y) / SPRITE_SIZE,
0.0,
rows as f64,
) as usize;
let mut collision_x = false; let mut collision_x = false;
let mut collision_y = false; let mut collision_y = false;
@ -429,10 +478,10 @@ impl Map {
for col in min_col..=max_col { for col in min_col..=max_col {
for row in min_row..=max_row { for row in min_row..=max_row {
let tile_left = col as f32 * SPRITE_SIZE_F32; let tile_left = col as f64 * SPRITE_SIZE;
let tile_top = row as f32 * SPRITE_SIZE_F32; let tile_top = row as f64 * SPRITE_SIZE;
let tile = Bbox::new(tile_left, tile_top, SPRITE_SIZE_F32, SPRITE_SIZE_F32); let tile = Bbox::new(tile_left, tile_top, SPRITE_SIZE, SPRITE_SIZE);
if !overlap(new, tile) { if !overlap(new, tile) {
continue; continue;
@ -440,11 +489,11 @@ impl Map {
// Collisions between feet and ground // Collisions between feet and ground
if self.collision_tiles[(row, col)].from_top if self.collision_tiles[(row, col)].from_top
&& old.top + old.height <= tile_top && old.position.y + old.size.y <= tile_top
&& new.top + new.height >= tile_top && new.position.y + new.size.y >= tile_top
{ {
collision_y = true; collision_y = true;
new.top = tile_top - new.height; new.position.y = tile_top - new.size.y;
} }
if !overlap(new, tile) { if !overlap(new, tile) {
@ -453,11 +502,11 @@ impl Map {
// Collisions between right and right wall // Collisions between right and right wall
if self.collision_tiles[(row, col)].from_left if self.collision_tiles[(row, col)].from_left
&& old.left + old.width <= tile_left && old.position.x + old.size.x <= tile_left
&& new.left + new.width >= tile_left && new.position.x + new.size.x >= tile_left
{ {
collision_x = true; collision_x = true;
new.left = tile_left - new.width; new.position.x = tile_left - new.size.x;
} }
if !overlap(new, tile) { if !overlap(new, tile) {
@ -466,11 +515,11 @@ impl Map {
// Collisions between left and left wall // Collisions between left and left wall
if self.collision_tiles[(row, col)].from_right if self.collision_tiles[(row, col)].from_right
&& old.left >= tile_left + SPRITE_SIZE_F32 && old.position.x >= tile_left + SPRITE_SIZE
&& new.left <= tile_left + SPRITE_SIZE_F32 && new.position.x <= tile_left + SPRITE_SIZE
{ {
collision_x = true; collision_x = true;
new.left = tile_left + SPRITE_SIZE_F32; new.position.x = tile_left + SPRITE_SIZE;
} }
if !overlap(new, tile) { if !overlap(new, tile) {
@ -479,39 +528,38 @@ impl Map {
// Collisions between head and roof // Collisions between head and roof
if self.collision_tiles[(row, col)].from_bottom if self.collision_tiles[(row, col)].from_bottom
&& old.top >= tile_top + SPRITE_SIZE_F32 && old.position.y >= tile_top + SPRITE_SIZE
&& new.top <= tile_top + SPRITE_SIZE_F32 && new.position.y <= tile_top + SPRITE_SIZE
{ {
collision_y = true; collision_y = true;
new.top = tile_top + SPRITE_SIZE_F32; new.position.y = tile_top + SPRITE_SIZE;
} }
} }
} }
// Collision between the player and left border of the level // Collision between the player and left border of the level
if new.left < 0.0 { if new.position.x < 0.0 {
new.left = 0.0; new.position.x = 0.0;
collision_x = true; collision_x = true;
} }
// Collision between the player and right border of the level // Collision between the player and right border of the level
if new.left > cols as f32 * SPRITE_SIZE_F32 { if new.position.x > cols as f64 * SPRITE_SIZE {
new.left = cols as f32 * SPRITE_SIZE_F32; new.position.x = cols as f64 * SPRITE_SIZE;
collision_x = true; collision_x = true;
} }
// Collision between the player and the void // Collision between the player and the void
if new.top > self.collision_tiles.rows() as f32 * SPRITE_SIZE_F32 { if new.position.y > self.collision_tiles.rows() as f64 * SPRITE_SIZE {
new.top = self.collision_tiles.rows() as f32 * SPRITE_SIZE_F32; new.position.y = self.collision_tiles.rows() as f64 * SPRITE_SIZE;
collision_y = true; collision_y = true;
damage = Damage::Death; death = true;
} }
let new_pos = Vector2::new(new.left, new.top);
match (collision_x, collision_y) { match (collision_x, collision_y) {
(true, true) => Some((CollisionAxis::Both, new_pos, damage)), (true, true) => Some((CollisionAxis::Both, new.position, death)),
(true, false) => Some((CollisionAxis::X, new_pos, damage)), (true, false) => Some((CollisionAxis::X, new.position, death)),
(false, true) => Some((CollisionAxis::Y, new_pos, damage)), (false, true) => Some((CollisionAxis::Y, new.position, death)),
(false, false) => None, (false, false) => None,
} }
} }

View File

@ -4,6 +4,7 @@ pub mod bbox;
pub mod character; pub mod character;
pub mod controls; pub mod controls;
pub mod event; pub mod event;
pub mod map;
pub mod math; pub mod math;
pub mod physics; pub mod physics;
pub mod scene; pub mod scene;

View File

@ -3,6 +3,7 @@
use std::time::Duration; use std::time::Duration;
use crate::engine::character::Character; use crate::engine::character::Character;
use crate::engine::event::Keyboard;
use crate::engine::map::Map; use crate::engine::map::Map;
use crate::engine::texture::SPRITE_SIZE; use crate::engine::texture::SPRITE_SIZE;
@ -37,8 +38,8 @@ impl Scene {
/// Adds a character to the scene. /// Adds a character to the scene.
pub fn add(&mut self, character: Character) { pub fn add(&mut self, character: Character) {
let mut character = character; let mut character = character;
character.position.x = self.map.entrance().1 * SPRITE_SIZE; character.position.x = self.map.entrance().1 as f64 * SPRITE_SIZE;
character.position.y = self.map.entrance().0 * SPRITE_SIZE; character.position.y = self.map.entrance().0 as f64 * SPRITE_SIZE;
self.characters.push(character); self.characters.push(character);
} }
@ -83,7 +84,7 @@ impl Scene {
// } // }
/// Updates the whole scene. /// Updates the whole scene.
pub fn update(&mut self, duration: &Duration) -> State { pub fn update(&mut self, duration: &Duration, keyboard: &Keyboard) -> State {
let mut state = State::Finished; let mut state = State::Finished;
for c in &mut self.characters { for c in &mut self.characters {
@ -95,7 +96,7 @@ impl Scene {
// Compute the offset between position and bbox // Compute the offset between position and bbox
let offset = old.position - c.position; let offset = old.position - c.position;
c.update(duration); c.update(duration, keyboard);
if let Some((axis, position, damage)) = self.map.collides_bbox(old, c.bbox()) { if let Some((axis, position, damage)) = self.map.collides_bbox(old, c.bbox()) {
c.position = position - offset; c.position = position - offset;
@ -143,7 +144,7 @@ impl Scene {
/// Trait that needs to be implemented for everything that can be updatable. /// Trait that needs to be implemented for everything that can be updatable.
pub trait Updatable { pub trait Updatable {
/// Updates the thing depending on the duration since last frame. /// Updates the thing depending on the duration since last frame.
fn update(&mut self, duration: &Duration); fn update(&mut self, duration: &Duration, keyboard: &Keyboard);
// /// Called when an event arrives. // /// Called when an event arrives.
// fn manage_event(&mut self, event: &Event); // fn manage_event(&mut self, event: &Event);