Working on inputs

This commit is contained in:
Thomas Forgione 2022-08-02 15:05:11 +02:00
parent df73f99345
commit 679d6ebe4f
3 changed files with 116 additions and 6 deletions

View File

@ -25,4 +25,5 @@ features = [
'Performance',
'Gamepad',
'GamepadEvent',
'GamepadButton',
]

View File

@ -20,7 +20,7 @@ pub enum Event {
}
/// The different actions that a user can do.
#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum Button {
/// The user asks to go to the left.
Left,
@ -64,11 +64,117 @@ impl InputManager {
events: VecDeque::new(),
}
}
/// Adds a gamepad to the input manager.
pub fn add_gamepad(&mut self, gamepad: web_sys::Gamepad) {
self.gamepads.push(Gamepad::new(gamepad));
}
/// Updates the gamepad states.
pub fn update(&mut self) {
for gamepad in &mut self.gamepads {
gamepad.update();
}
}
}
/// Holds the gamepad information.
#[derive(Clone)]
pub struct Gamepad {
/// The inner gamepad.
/// The javascript gamepad object.
inner: web_sys::Gamepad,
/// What buttons are pressed or released.
state: HashMap<Button, bool>,
}
impl Gamepad {
/// Creates a new gamepad from its javascript gamepad.
pub fn new(inner: web_sys::Gamepad) -> Gamepad {
Gamepad {
inner,
state: HashMap::new(),
}
}
/// Updates the state of the gamepad and adds the corresponding events to the deque.
pub fn update(&mut self) -> VecDeque<Event> {
let mut events = VecDeque::new();
const BUTTONS: [Button; 4] = [
Button::Button0,
Button::Button1,
Button::Button2,
Button::Button3,
];
for button in BUTTONS {
// Finds the real state of the button
let is_pressed = self.is_js_pressed(button);
// Updates the map and returns the old state of the button
let was_pressed = self.state.insert(button, is_pressed).unwrap_or(false);
if was_pressed && !is_pressed {
// Button was released
events.push_back(Event::ButtonReleased(button));
}
if is_pressed && !was_pressed {
// Button was pressed
events.push_back(Event::ButtonPressed(button));
}
}
events
}
/// Checks if a button is pressed.
pub fn is_pressed(&self, button: Button) -> bool {
*self.state.get(&button).unwrap_or(&false)
}
/// Utility function to really check the state of the button.
fn is_js_pressed(&self, button: Button) -> bool {
let buttons = self.inner.buttons();
match button {
Button::Left => false,
Button::Right => false,
Button::Up => false,
Button::Down => false,
Button::Button0 => Into::<web_sys::GamepadButton>::into(buttons.get(0)).pressed(),
Button::Button1 => Into::<web_sys::GamepadButton>::into(buttons.get(0)).pressed(),
Button::Button2 => Into::<web_sys::GamepadButton>::into(buttons.get(0)).pressed(),
Button::Button3 => Into::<web_sys::GamepadButton>::into(buttons.get(0)).pressed(),
}
}
}
/// A helper to easily deal with inputs.
#[derive(Clone)]
pub struct Inputs(Rc<RefCell<InputManager>>);
impl Inputs {
/// Creates a new inputs object.
pub fn new(window: &web_sys::Window) -> Result<Inputs> {
let inputs = Inputs(Rc::new(RefCell::new(InputManager::new())));
let clone = inputs.clone();
let cb = Closure::<dyn FnMut(_)>::new(move |event: web_sys::GamepadEvent| {
let mut inner = clone.0.borrow_mut();
inner.add_gamepad(event.gamepad().unwrap());
});
window.add_event_listener_with_callback("gamepadconnected", cb.as_ref().unchecked_ref())?;
Ok(inputs)
}
/// Updates the inputs.
///
/// This function needs to be called at each frame.
pub fn update(&mut self) {
let mut inner = self.0.borrow_mut();
inner.update();
}
}

View File

@ -21,7 +21,7 @@ use wasm_bindgen::JsCast;
use crate::engine::bbox::Bbox;
use crate::engine::character::Character;
use crate::engine::controls::Controls;
use crate::engine::input::InputManager;
use crate::engine::input::Inputs;
use crate::engine::map::Map;
use crate::engine::math::now;
use crate::engine::scene::{Scene, State};
@ -118,7 +118,7 @@ pub struct Engine {
pub textures: TextureManager,
/// The input manager.
pub inputs: InputManager,
pub inputs: Inputs,
/// The web page window.
pub window: web_sys::Window,
@ -160,7 +160,7 @@ impl Engine {
scene,
after_loop: now(&performance),
textures: TextureManager::new()?,
inputs: InputManager::new(),
inputs: Inputs::new(&window)?,
window,
document,
context,
@ -170,11 +170,14 @@ impl Engine {
/// Triggers the update of the model of the engine.
pub fn update(&mut self) -> Result<()> {
// Manage the physics
// Manage time correctly
let now = now(&self.performance);
let duration = unwrap!(now.duration_since(self.after_loop).ok());
self.after_loop = now;
// Update inputs that need to be updated
self.inputs.update();
if self.document.has_focus()? {
// Manage events
// while let Some(event) = inner.keyboard.pop() {