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;
/// This struct represents a bounding box.
#[derive(Copy, Clone)]
pub struct Bbox {
/// The position of the top right corner of the box.
pub position: Vector,

View File

@ -3,17 +3,13 @@
use std::time::{Duration, Instant};
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::scene::Updatable;
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.
pub enum Side {
/// The character looks to the left.
@ -148,11 +144,11 @@ impl 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);
if let Some(ref controls) = self.controls {
force += controls.direction();
force += controls.direction(keyboard);
}
if let Some(side) = Side::from_force(force) {
@ -182,7 +178,7 @@ impl Updatable for Character {
}
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,
};

View File

@ -1,6 +1,6 @@
//! 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;
/// The different actions that a user can do.
@ -52,9 +52,9 @@ impl Controls {
}
/// Returns the direction of the controls.
pub fn direction(&self) -> Vector {
pub fn direction(&self, keyboard: &Keyboard) -> Vector {
match self {
Controls::Keyboard(ref map) => map.direction(),
Controls::Keyboard(ref map) => map.direction(keyboard),
// Controls::Gamepad(ref map) => map.direction(),
}
}
@ -106,14 +106,14 @@ impl KeyboardMap {
}
/// 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);
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;
}
if self.left_key.is_pressed() {
if keyboard.is_key_pressed(self.left_key) {
ret -= RIGHT;
}
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::path::Path;
use sfml::graphics::{FloatRect, IntRect};
use sfml::system::Vector2;
use crate::engine::character::Damage;
use crate::engine::bbox::Bbox;
use crate::engine::math::{clamp, Matrix};
use crate::engine::renderer::Drawable;
use crate::engine::texture::{byte_to_index, Texture, SPRITE_SIZE_F32, SPRITE_SIZE_I32};
use crate::{Error, Result};
use crate::engine::texture::SPRITE_SIZE;
use crate::engine::vector::Vector;
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.
#[derive(Copy, Clone)]
@ -175,23 +227,23 @@ pub struct PositionedTile {
pub collision: CollisionTile,
/// The position of the positioned tile.
pub position: (f32, f32),
pub position: Vector,
}
impl Drawable for PositionedTile {
fn texture(&self) -> Texture {
Texture::Overworld
}
fn texture_rect(&self) -> IntRect {
let offset = self.graphic.offset();
IntRect::new(offset.0, offset.1, SPRITE_SIZE_I32, SPRITE_SIZE_I32)
}
fn position(&self) -> Vector2<f32> {
self.position.into()
}
}
// impl Drawable for PositionedTile {
// fn texture(&self) -> Texture {
// Texture::Overworld
// }
//
// fn texture_rect(&self) -> Bbox {
// let offset = self.graphic.offset();
// Bbox::new(offset.x, offset.x, SPRITE_SIZE, SPRITE_SIZE)
// }
//
// fn position(&self) -> Vector {
// self.position
// }
// }
/// The map represents the tiles contained in a level.
#[derive(Clone)]
@ -219,14 +271,6 @@ impl Map {
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.
pub fn from_str(text: &str) -> Result<Map> {
let split = text.split('\n').collect::<Vec<_>>();
@ -390,7 +434,7 @@ impl Map {
PositionedTile {
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),
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.
///
/// Returns the new correct position.
pub fn collides_bbox(
&self,
old: Bbox,
new: Bbox,
) -> Option<(CollisionAxis, Vector2<f32>, Damage)> {
let mut damage = Damage::None;
pub fn collides_bbox(&self, old: Bbox, new: Bbox) -> Option<(CollisionAxis, Vector, bool)> {
let mut death = false;
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;
let min_col = clamp(new.position.x / SPRITE_SIZE, 0.0, cols as f64) 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_row = clamp((new.top + new.height) / SPRITE_SIZE_F32, 0.0, rows as f32) as usize;
let max_col = clamp(
(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_y = false;
@ -429,10 +478,10 @@ impl Map {
for col in min_col..=max_col {
for row in min_row..=max_row {
let tile_left = col as f32 * SPRITE_SIZE_F32;
let tile_top = row as f32 * SPRITE_SIZE_F32;
let tile_left = col as f64 * SPRITE_SIZE;
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) {
continue;
@ -440,11 +489,11 @@ impl Map {
// Collisions between feet and ground
if self.collision_tiles[(row, col)].from_top
&& old.top + old.height <= tile_top
&& new.top + new.height >= tile_top
&& old.position.y + old.size.y <= tile_top
&& new.position.y + new.size.y >= tile_top
{
collision_y = true;
new.top = tile_top - new.height;
new.position.y = tile_top - new.size.y;
}
if !overlap(new, tile) {
@ -453,11 +502,11 @@ impl Map {
// Collisions between right and right wall
if self.collision_tiles[(row, col)].from_left
&& old.left + old.width <= tile_left
&& new.left + new.width >= tile_left
&& old.position.x + old.size.x <= tile_left
&& new.position.x + new.size.x >= tile_left
{
collision_x = true;
new.left = tile_left - new.width;
new.position.x = tile_left - new.size.x;
}
if !overlap(new, tile) {
@ -466,11 +515,11 @@ impl Map {
// Collisions between left and left wall
if self.collision_tiles[(row, col)].from_right
&& old.left >= tile_left + SPRITE_SIZE_F32
&& new.left <= tile_left + SPRITE_SIZE_F32
&& old.position.x >= tile_left + SPRITE_SIZE
&& new.position.x <= tile_left + SPRITE_SIZE
{
collision_x = true;
new.left = tile_left + SPRITE_SIZE_F32;
new.position.x = tile_left + SPRITE_SIZE;
}
if !overlap(new, tile) {
@ -479,39 +528,38 @@ impl Map {
// Collisions between head and roof
if self.collision_tiles[(row, col)].from_bottom
&& old.top >= tile_top + SPRITE_SIZE_F32
&& new.top <= tile_top + SPRITE_SIZE_F32
&& old.position.y >= tile_top + SPRITE_SIZE
&& new.position.y <= tile_top + SPRITE_SIZE
{
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
if new.left < 0.0 {
new.left = 0.0;
if new.position.x < 0.0 {
new.position.x = 0.0;
collision_x = true;
}
// Collision between the player and right border of the level
if new.left > cols as f32 * SPRITE_SIZE_F32 {
new.left = cols as f32 * SPRITE_SIZE_F32;
if new.position.x > cols as f64 * SPRITE_SIZE {
new.position.x = cols as f64 * SPRITE_SIZE;
collision_x = true;
}
// Collision between the player and the void
if new.top > self.collision_tiles.rows() as f32 * SPRITE_SIZE_F32 {
new.top = self.collision_tiles.rows() as f32 * SPRITE_SIZE_F32;
if new.position.y > self.collision_tiles.rows() as f64 * SPRITE_SIZE {
new.position.y = self.collision_tiles.rows() as f64 * SPRITE_SIZE;
collision_y = true;
damage = Damage::Death;
death = true;
}
let new_pos = Vector2::new(new.left, new.top);
match (collision_x, collision_y) {
(true, true) => Some((CollisionAxis::Both, new_pos, damage)),
(true, false) => Some((CollisionAxis::X, new_pos, damage)),
(false, true) => Some((CollisionAxis::Y, new_pos, damage)),
(true, true) => Some((CollisionAxis::Both, new.position, death)),
(true, false) => Some((CollisionAxis::X, new.position, death)),
(false, true) => Some((CollisionAxis::Y, new.position, death)),
(false, false) => None,
}
}

View File

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

View File

@ -3,6 +3,7 @@
use std::time::Duration;
use crate::engine::character::Character;
use crate::engine::event::Keyboard;
use crate::engine::map::Map;
use crate::engine::texture::SPRITE_SIZE;
@ -37,8 +38,8 @@ impl Scene {
/// Adds a character to the scene.
pub fn add(&mut self, character: Character) {
let mut character = character;
character.position.x = self.map.entrance().1 * SPRITE_SIZE;
character.position.y = self.map.entrance().0 * SPRITE_SIZE;
character.position.x = self.map.entrance().1 as f64 * SPRITE_SIZE;
character.position.y = self.map.entrance().0 as f64 * SPRITE_SIZE;
self.characters.push(character);
}
@ -83,7 +84,7 @@ impl 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;
for c in &mut self.characters {
@ -95,7 +96,7 @@ impl Scene {
// Compute the offset between position and bbox
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()) {
c.position = position - offset;
@ -143,7 +144,7 @@ impl Scene {
/// Trait that needs to be implemented for everything that can be updatable.
pub trait Updatable {
/// 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.
// fn manage_event(&mut self, event: &Event);