Preparing for massive refactoring

This commit is contained in:
Thomas Forgione 2022-08-01 18:16:45 +02:00
parent c771d1ccea
commit 6a1cc8876f
5 changed files with 62 additions and 376 deletions

View File

@ -3,8 +3,8 @@
use std::time::{Duration, SystemTime, UNIX_EPOCH}; use std::time::{Duration, SystemTime, UNIX_EPOCH};
use crate::engine::bbox::Bbox; use crate::engine::bbox::Bbox;
use crate::engine::controls::{Action, Controls}; use crate::engine::controls::Controls;
use crate::engine::event::{Event, Keyboard}; use crate::engine::event::Action;
use crate::engine::math::{clamp, duration_as_f64, duration_as_frame}; use crate::engine::math::{clamp, duration_as_f64, duration_as_frame};
use crate::engine::physics; use crate::engine::physics;
use crate::engine::scene::Updatable; use crate::engine::scene::Updatable;
@ -74,9 +74,6 @@ pub struct Character {
/// Whether the character is walking or not. /// Whether the character is walking or not.
walking: bool, walking: bool,
/// Indicates that the player has released the jump button.
can_jump: bool,
} }
impl Character { impl Character {
@ -90,7 +87,6 @@ impl Character {
jump_counter: 1, jump_counter: 1,
max_jump: 1, max_jump: 1,
animation_timer: UNIX_EPOCH, animation_timer: UNIX_EPOCH,
can_jump: true,
walking: false, walking: false,
} }
} }
@ -107,7 +103,7 @@ impl Character {
/// Makes the character jump. /// Makes the character jump.
pub fn jump(&mut self) { pub fn jump(&mut self) {
if self.can_jump && self.jump_counter > 0 { if self.jump_counter > 0 {
self.jump_counter -= 1; self.jump_counter -= 1;
self.speed.y = physics::JUMP_SPEED.y; self.speed.y = physics::JUMP_SPEED.y;
} }
@ -152,11 +148,11 @@ impl Character {
} }
impl Updatable for Character { impl Updatable for Character {
fn update(&mut self, now: SystemTime, duration: Duration, keyboard: &Keyboard) { fn update(&mut self, now: SystemTime, duration: Duration) {
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(keyboard); // force += controls.direction();
} }
if let Some(side) = Side::from_force(force) { if let Some(side) = Side::from_force(force) {
@ -186,7 +182,7 @@ impl Updatable for Character {
} }
let limit = match self.controls { let limit = match self.controls {
Some(ref 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,
}; };
@ -196,21 +192,11 @@ impl Updatable for Character {
self.position += self.speed * duration; self.position += self.speed * duration;
} }
fn manage_event(&mut self, event: &Event) { /// An action was asked to the character.
let action = if let Some(ref controls) = self.controls { fn manage_action(&mut self, action: Action) {
controls.convert(event)
} else {
None
};
match action { match action {
Some(Action::Jump(true)) => { Action::Button1 => {
self.jump(); self.jump();
self.can_jump = false;
}
Some(Action::Jump(false)) => {
self.can_jump = true;
} }
_ => (), _ => (),

View File

@ -1,179 +1,4 @@
//! This module helps to deal with controls. //! This module helps to deal with controls.
use crate::engine::event::{Event, Key, Keyboard}; /// The different types of controls.
use crate::engine::vector::Vector; pub enum Controls {}
use crate::log;
/// The different actions that a user can do.
pub enum Action {
/// The jump button.
///
/// A bool at true means that the button was pressed,
/// A bool at false means that the button was released.
Jump(bool),
}
pub enum Controls {
/// A keyboard controller.
Keyboard(KeyboardMap),
/// A gamepad controller.
Gamepad(GamepadMap),
}
impl Controls {
/// Returns the default keyboard controls.
pub fn default_keyboard() -> Controls {
Controls::Keyboard(KeyboardMap::default())
}
/// Returns the default gamepad controls from id.
///
/// Returns None if the gamepad corresponding to the id is not connected.
pub fn default_gamepad(gamepad: web_sys::Gamepad) -> Controls {
Controls::Gamepad(GamepadMap::from_gamepad(gamepad))
}
// /// Returns the default gamepad controls from id.
// ///
// /// Returns None if the gamepad corresponding to the id is not connected.
// pub fn all_gamepads() -> Vec<Controls> {
// GamepadMap::all()
// .into_iter()
// .map(|x| Controls::Gamepad(x))
// .collect()
// }
/// Converts an event and depending on the config, returns the corresponding action.
pub fn convert(&self, event: &Event) -> Option<Action> {
match self {
Controls::Keyboard(ref map) => map.convert(event),
Controls::Gamepad(ref map) => map.convert(event),
}
}
/// Returns the direction of the controls.
pub fn direction(&self, keyboard: &Keyboard) -> Vector {
match self {
Controls::Keyboard(ref map) => map.direction(keyboard),
Controls::Gamepad(ref map) => map.direction(),
}
}
/// Returns whether the running key is pressed.
pub fn is_running(&self) -> bool {
false
// match self {
// Controls::Keyboard(ref map) => map.is_running(),
// Controls::Gamepad(ref map) => map.is_running(),
// }
}
}
/// A map between keyboard keys and actions.
#[derive(Copy, Clone)]
pub struct KeyboardMap {
/// The key corresponding to the jump button.
jump_key: Key,
/// The key corresponding to the run button.
run_key: Key,
/// The key corresponding to the left button.
left_key: Key,
/// The key corresponding to the right button.
right_key: Key,
}
impl KeyboardMap {
/// Creates the default keyboard config.
pub fn default() -> KeyboardMap {
KeyboardMap {
jump_key: Key::Space,
run_key: Key::ArrowUp,
left_key: Key::ArrowLeft,
right_key: Key::ArrowRight,
}
}
/// Converts an event and depending on the config, returns the corresponding action.
pub fn convert(&self, event: &Event) -> Option<Action> {
match event {
Event::KeyPressed(code) if *code == self.jump_key => Some(Action::Jump(true)),
Event::KeyReleased(code) if *code == self.jump_key => Some(Action::Jump(false)),
_ => None,
}
}
/// Returns the direction of the keys.
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 keyboard.is_key_pressed(self.right_key) {
ret += RIGHT;
}
if keyboard.is_key_pressed(self.left_key) {
ret -= RIGHT;
}
ret
}
}
/// A map between gamepad buttons and actions.
#[derive(Clone)]
pub struct GamepadMap {
/// Id of the gamepad.
inner: web_sys::Gamepad,
/// Number of the jump button.
jump_button: u32,
/// Number of the run button.
run_button: u32,
// /// Left / Right axis.
// left_right_axis: Axis,
}
impl GamepadMap {
/// Creates a gamepad map from a javascript gamepad.
pub fn from_gamepad(gamepad: web_sys::Gamepad) -> GamepadMap {
GamepadMap {
inner: gamepad,
jump_button: 0,
run_button: 3,
}
}
/// Converts an event and depending on the config, returns the corresponding action.
pub fn convert(&self, event: &Event) -> Option<Action> {
None
// match event {
// Event::JoystickButtonPressed { joystickid, button }
// if *joystickid == self.id && *button == self.jump_button =>
// {
// Some(Action::Jump(true))
// }
// Event::JoystickButtonReleased { joystickid, button }
// if *joystickid == self.id && *button == self.jump_button =>
// {
// Some(Action::Jump(false))
// }
// _ => None,
// }
}
/// Returns the direction of the directionnal buttons of the gamepad.
pub fn direction(&self) -> Vector {
Vector::new(0.0, 0.0)
// Vector2::new(axis_position(self.id, self.left_right_axis) / 100.0, 0.0)
}
// /// Returns whether the run button is held down.
// pub fn is_running(&self) -> bool {
// is_button_pressed(self.id, self.run_button)
// }
}

View File

@ -9,146 +9,30 @@ use wasm_bindgen::JsCast;
use crate::Result; use crate::Result;
/// The state of the keyboard. /// The different actions that a user can do.
#[derive(Clone)]
pub struct Keyboard {
/// The inner keyboard.
inner: Rc<RefCell<InnerKeyboard>>,
}
impl Keyboard {
/// Checks wether a key is pressed or not.
pub fn is_key_pressed(&self, key: Key) -> bool {
let mut b = self.inner.borrow_mut();
*b.keys.entry(key).or_insert(false)
}
/// Receives and treats an event.
pub fn manage_event(&self, event: Event) {
let mut b = self.inner.borrow_mut();
match event {
Event::KeyPressed(x) => *b.keys.entry(x).or_insert(true) = true,
Event::KeyReleased(x) => *b.keys.entry(x).or_insert(false) = false,
}
b.events.push_back(event);
}
/// Gets an event from the event stack.
pub fn pop(&self) -> Option<Event> {
self.inner.borrow_mut().events.pop_front()
}
}
impl Keyboard {
/// Initializes the keyboard.
pub fn new(document: &web_sys::Document) -> Result<Keyboard> {
let inner = Rc::new(RefCell::new(InnerKeyboard::new()));
let clone = Keyboard {
inner: inner.clone(),
};
let down_cb = Closure::<dyn FnMut(_)>::new(move |event: web_sys::KeyboardEvent| {
if let Some(event) = Event::from_js(true, event) {
clone.manage_event(event);
}
});
document.set_onkeydown(Some(down_cb.as_ref().unchecked_ref()));
down_cb.forget();
let clone = Keyboard {
inner: inner.clone(),
};
let up_cb = Closure::<dyn FnMut(_)>::new(move |event: web_sys::KeyboardEvent| {
if let Some(event) = Event::from_js(false, event) {
clone.manage_event(event);
}
});
document.set_onkeyup(Some(up_cb.as_ref().unchecked_ref()));
up_cb.forget();
Ok(Keyboard { inner })
}
}
/// The state of the keyboard.
#[derive(Clone)]
pub struct InnerKeyboard {
/// Holds the state of the keys.
keys: HashMap<Key, bool>,
/// The list of events to be processed.
events: VecDeque<Event>,
}
impl InnerKeyboard {
/// Creates a new inner arrowboard.
pub fn new() -> InnerKeyboard {
InnerKeyboard {
keys: HashMap::new(),
events: VecDeque::new(),
}
}
}
/// The different events that can occur.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum Event { pub enum Action {
/// A key was pressed down. /// The user asks to go to the left.
KeyPressed(Key), GoLeft,
/// A key was released. /// The user asks to go to the right.
KeyReleased(Key), GoRight,
}
/// The user asks to go up.
/// The different key we cant to support. GoUp,
#[derive(Hash, PartialEq, Eq, Copy, Clone)]
pub enum Key { /// The user asks to go down.
/// The left arrow key. GoDown,
ArrowLeft,
/// The user asks to do the main action or validate.
/// The right arrow key. Button1,
ArrowRight,
/// The user asks to do the secondary action.
/// The up arrow key. Button2,
ArrowUp,
/// The user asks to do the tertiary action.
/// The bottom arrow key. Button3,
ArrowDown,
/// The user asks to do the 4th action or cancel.
/// The space key. Button4,
Space,
}
impl Key {
/// Tries and converts a javascript key to our key type.
pub fn from_str(string: &str) -> Option<Key> {
match string {
"ArrowLeft" => Some(Key::ArrowLeft),
"ArrowRight" => Some(Key::ArrowRight),
"ArrowUp" => Some(Key::ArrowUp),
"ArrowDown" => Some(Key::ArrowDown),
"Space" => Some(Key::Space),
_ => None,
}
}
}
impl Event {
/// Tries and converts a javacript event to our event type.
pub fn from_js(down: bool, event: web_sys::KeyboardEvent) -> Option<Event> {
let key = Key::from_str(&event.code())?;
let event = if down {
Some(Event::KeyPressed(key))
} else {
Some(Event::KeyReleased(key))
};
event
}
} }

View File

@ -20,8 +20,7 @@ use wasm_bindgen::JsCast;
use crate::engine::bbox::Bbox; use crate::engine::bbox::Bbox;
use crate::engine::character::Character; use crate::engine::character::Character;
use crate::engine::controls::{Controls, GamepadMap}; use crate::engine::controls::Controls;
use crate::engine::event::{Key, Keyboard};
use crate::engine::map::Map; use crate::engine::map::Map;
use crate::engine::math::now; use crate::engine::math::now;
use crate::engine::scene::{Scene, State}; use crate::engine::scene::{Scene, State};
@ -79,7 +78,7 @@ impl Engine {
let map = Map::from_str(include_str!("../../static/levels/level1.lvl")).unwrap(); let map = Map::from_str(include_str!("../../static/levels/level1.lvl")).unwrap();
let mut scene = Scene::from_map(map); let mut scene = Scene::from_map(map);
let character = Character::with_controls(Controls::default_keyboard()); let character = Character::new();
scene.add(character); scene.add(character);
let inner = InnerEngine::new(&document, &performance, scene)?; let inner = InnerEngine::new(&document, &performance, scene)?;
@ -159,20 +158,20 @@ impl Engine {
if self.document.has_focus()? { if self.document.has_focus()? {
// Manage events // Manage events
while let Some(event) = inner.keyboard.pop() { // while let Some(event) = inner.keyboard.pop() {
inner.scene.manage_event(&event); // inner.scene.manage_action(&action);
} // }
let keyboard = inner.keyboard.clone(); // let keyboard = inner.keyboard.clone();
if inner.scene.update(now, duration, &keyboard) == State::Finished { // if inner.scene.update(now, duration) == State::Finished {
let map = Map::from_str(include_str!("../../static/levels/level1.lvl")).unwrap(); // let map = Map::from_str(include_str!("../../static/levels/level1.lvl")).unwrap();
let mut scene = Scene::from_map(map); // let mut scene = Scene::from_map(map);
let character = Character::with_controls(Controls::default_keyboard()); // let character = Character::with_controls(Controls::default_keyboard());
scene.add(character); // scene.add(character);
inner.scene = scene; // inner.scene = scene;
} // }
} }
Ok(()) Ok(())
@ -239,12 +238,6 @@ pub struct InnerEngine {
/// The time when the loop is done. /// The time when the loop is done.
pub after_loop: SystemTime, pub after_loop: SystemTime,
/// The keyboard.
pub keyboard: Keyboard,
/// The gamepads.
pub gamepads: Vec<GamepadMap>,
/// The texture manager. /// The texture manager.
pub textures: TextureManager, pub textures: TextureManager,
} }
@ -259,20 +252,18 @@ impl InnerEngine {
Ok(InnerEngine { Ok(InnerEngine {
scene, scene,
after_loop: now(&performance), after_loop: now(&performance),
keyboard: Keyboard::new(document)?,
gamepads: vec![],
textures: TextureManager::new()?, textures: TextureManager::new()?,
}) })
} }
/// Adds a gamepad. /// Adds a gamepad.
pub fn add_gamepad(&mut self, gamepad: &web_sys::GamepadEvent) { pub fn add_gamepad(&mut self, gamepad: &web_sys::GamepadEvent) {
let gamepad = GamepadMap::from_gamepad(gamepad.gamepad().unwrap()); // let gamepad = GamepadMap::from_gamepad(gamepad.gamepad().unwrap());
let clone = gamepad.clone(); // let clone = gamepad.clone();
self.gamepads.push(clone); // self.gamepads.push(clone);
let controlable = self.scene.controlable_mut().unwrap(); // let controlable = self.scene.controlable_mut().unwrap();
controlable.set_controls(Some(Controls::Gamepad(gamepad))); // controlable.set_controls(Some(Controls::Gamepad(gamepad)));
} }
} }

View File

@ -4,7 +4,7 @@ use std::time::{Duration, SystemTime};
use crate::engine::bbox::Bbox; use crate::engine::bbox::Bbox;
use crate::engine::character::Character; use crate::engine::character::Character;
use crate::engine::event::{Event, Keyboard}; use crate::engine::event::Action;
use crate::engine::map::Map; use crate::engine::map::Map;
use crate::engine::texture::SPRITE_SIZE; use crate::engine::texture::SPRITE_SIZE;
@ -95,7 +95,7 @@ impl Scene {
} }
/// Updates the whole scene. /// Updates the whole scene.
pub fn update(&mut self, now: SystemTime, duration: Duration, keyboard: &Keyboard) -> State { pub fn update(&mut self, now: SystemTime, duration: Duration) -> State {
let mut state = State::Running; let mut state = State::Running;
for c in &mut self.characters { for c in &mut self.characters {
@ -107,7 +107,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(now, duration, keyboard); c.update(now, duration);
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;
@ -132,10 +132,10 @@ impl Scene {
state state
} }
/// Transfers an event to the elements contained in the scene that should receive events. /// Transfers an action to the elements contained in the scene that should receive actions.
pub fn manage_event(&mut self, event: &Event) { pub fn manage_action(&mut self, action: Action) {
for c in &mut self.characters { for c in &mut self.characters {
c.manage_event(event); c.manage_action(action);
} }
} }
@ -153,8 +153,8 @@ 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, now: SystemTime, duration: Duration, keyboard: &Keyboard); fn update(&mut self, now: SystemTime, duration: Duration);
/// Called when an event arrives. /// Called when an action arrives.
fn manage_event(&mut self, event: &Event); fn manage_action(&mut self, action: Action);
} }