Working on inputs
This commit is contained in:
parent
df73f99345
commit
679d6ebe4f
@ -25,4 +25,5 @@ features = [
|
|||||||
'Performance',
|
'Performance',
|
||||||
'Gamepad',
|
'Gamepad',
|
||||||
'GamepadEvent',
|
'GamepadEvent',
|
||||||
|
'GamepadButton',
|
||||||
]
|
]
|
||||||
|
@ -20,7 +20,7 @@ pub enum Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The different actions that a user can do.
|
/// The different actions that a user can do.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Button {
|
pub enum Button {
|
||||||
/// The user asks to go to the left.
|
/// The user asks to go to the left.
|
||||||
Left,
|
Left,
|
||||||
@ -64,11 +64,117 @@ impl InputManager {
|
|||||||
events: VecDeque::new(),
|
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.
|
/// Holds the gamepad information.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Gamepad {
|
pub struct Gamepad {
|
||||||
/// The inner gamepad.
|
/// The javascript gamepad object.
|
||||||
inner: web_sys::Gamepad,
|
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::bbox::Bbox;
|
||||||
use crate::engine::character::Character;
|
use crate::engine::character::Character;
|
||||||
use crate::engine::controls::Controls;
|
use crate::engine::controls::Controls;
|
||||||
use crate::engine::input::InputManager;
|
use crate::engine::input::Inputs;
|
||||||
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};
|
||||||
@ -118,7 +118,7 @@ pub struct Engine {
|
|||||||
pub textures: TextureManager,
|
pub textures: TextureManager,
|
||||||
|
|
||||||
/// The input manager.
|
/// The input manager.
|
||||||
pub inputs: InputManager,
|
pub inputs: Inputs,
|
||||||
|
|
||||||
/// The web page window.
|
/// The web page window.
|
||||||
pub window: web_sys::Window,
|
pub window: web_sys::Window,
|
||||||
@ -160,7 +160,7 @@ impl Engine {
|
|||||||
scene,
|
scene,
|
||||||
after_loop: now(&performance),
|
after_loop: now(&performance),
|
||||||
textures: TextureManager::new()?,
|
textures: TextureManager::new()?,
|
||||||
inputs: InputManager::new(),
|
inputs: Inputs::new(&window)?,
|
||||||
window,
|
window,
|
||||||
document,
|
document,
|
||||||
context,
|
context,
|
||||||
@ -170,11 +170,14 @@ impl Engine {
|
|||||||
|
|
||||||
/// Triggers the update of the model of the engine.
|
/// Triggers the update of the model of the engine.
|
||||||
pub fn update(&mut self) -> Result<()> {
|
pub fn update(&mut self) -> Result<()> {
|
||||||
// Manage the physics
|
// Manage time correctly
|
||||||
let now = now(&self.performance);
|
let now = now(&self.performance);
|
||||||
let duration = unwrap!(now.duration_since(self.after_loop).ok());
|
let duration = unwrap!(now.duration_since(self.after_loop).ok());
|
||||||
self.after_loop = now;
|
self.after_loop = now;
|
||||||
|
|
||||||
|
// Update inputs that need to be updated
|
||||||
|
self.inputs.update();
|
||||||
|
|
||||||
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() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user