Working on inputs
This commit is contained in:
parent
df73f99345
commit
679d6ebe4f
@ -25,4 +25,5 @@ features = [
|
||||
'Performance',
|
||||
'Gamepad',
|
||||
'GamepadEvent',
|
||||
'GamepadButton',
|
||||
]
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user