Working on gamepads

This commit is contained in:
Thomas Forgione 2022-08-01 16:54:11 +02:00
parent 2858e3d5ec
commit c771d1ccea
5 changed files with 114 additions and 15 deletions

View File

@ -23,4 +23,6 @@ features = [
'HtmlImageElement', 'HtmlImageElement',
'Window', 'Window',
'Performance', 'Performance',
'Gamepad',
'GamepadEvent',
] ]

View File

@ -135,6 +135,11 @@ impl Character {
&self.controls &self.controls
} }
/// Changes the controls.
pub fn set_controls(&mut self, controls: Option<Controls>) {
self.controls = controls;
}
/// Returns a view that looks at the character. /// Returns a view that looks at the character.
pub fn view(&self) -> Bbox { pub fn view(&self) -> Bbox {
Bbox::from_center_and_size(self.position, Vector::new(24.0 * 16.0, 24.0 * 9.0)) Bbox::from_center_and_size(self.position, Vector::new(24.0 * 16.0, 24.0 * 9.0))

View File

@ -16,6 +16,9 @@ pub enum Action {
pub enum Controls { pub enum Controls {
/// A keyboard controller. /// A keyboard controller.
Keyboard(KeyboardMap), Keyboard(KeyboardMap),
/// A gamepad controller.
Gamepad(GamepadMap),
} }
impl Controls { impl Controls {
@ -24,15 +27,12 @@ impl Controls {
Controls::Keyboard(KeyboardMap::default()) Controls::Keyboard(KeyboardMap::default())
} }
// /// Returns the default gamepad controls from id. /// Returns the default gamepad controls from id.
// /// ///
// /// Returns None if the gamepad corresponding to the id is not connected. /// Returns None if the gamepad corresponding to the id is not connected.
// pub fn default_gamepad_from_id(id: u32) -> Option<Controls> { pub fn default_gamepad(gamepad: web_sys::Gamepad) -> Controls {
// match GamepadMap::from_id(id) { Controls::Gamepad(GamepadMap::from_gamepad(gamepad))
// Some(map) => Some(Controls::Gamepad(map)), }
// None => None,
// }
// }
// /// Returns the default gamepad controls from id. // /// Returns the default gamepad controls from id.
// /// // ///
@ -48,7 +48,7 @@ impl Controls {
pub fn convert(&self, event: &Event) -> Option<Action> { pub fn convert(&self, event: &Event) -> Option<Action> {
match self { match self {
Controls::Keyboard(ref map) => map.convert(event), Controls::Keyboard(ref map) => map.convert(event),
// Controls::Gamepad(ref map) => map.convert(event), Controls::Gamepad(ref map) => map.convert(event),
} }
} }
@ -56,7 +56,7 @@ impl Controls {
pub fn direction(&self, keyboard: &Keyboard) -> Vector { pub fn direction(&self, keyboard: &Keyboard) -> Vector {
match self { match self {
Controls::Keyboard(ref map) => map.direction(keyboard), Controls::Keyboard(ref map) => map.direction(keyboard),
// Controls::Gamepad(ref map) => map.direction(), Controls::Gamepad(ref map) => map.direction(),
} }
} }
@ -120,3 +120,60 @@ impl KeyboardMap {
ret 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

@ -20,7 +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; use crate::engine::controls::{Controls, GamepadMap};
use crate::engine::event::{Key, Keyboard}; 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;
@ -84,13 +84,24 @@ impl Engine {
let inner = InnerEngine::new(&document, &performance, scene)?; let inner = InnerEngine::new(&document, &performance, scene)?;
let inner = Rc::new(RefCell::new(inner));
let window = Rc::new(window); let window = Rc::new(window);
let document = Rc::new(document); let document = Rc::new(document);
let performance = Rc::new(performance); let performance = Rc::new(performance);
let context = Rc::new(context); let context = Rc::new(context);
let clone = inner.clone();
let cb = Closure::<dyn FnMut(_)>::new(move |event: web_sys::GamepadEvent| {
let mut inner = clone.borrow_mut();
inner.add_gamepad(&event);
});
(*window).add_event_listener_with_callback("gamepadconnected", cb.as_ref().unchecked_ref());
cb.forget();
Ok(Engine { Ok(Engine {
inner: Rc::new(RefCell::new(inner)), inner,
window, window,
document, document,
performance, performance,
@ -146,7 +157,7 @@ impl Engine {
let duration = unwrap!(now.duration_since(inner.after_loop).ok()); let duration = unwrap!(now.duration_since(inner.after_loop).ok());
inner.after_loop = now; inner.after_loop = now;
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_event(&event);
@ -231,6 +242,9 @@ pub struct InnerEngine {
/// The keyboard. /// The keyboard.
pub keyboard: Keyboard, pub keyboard: Keyboard,
/// The gamepads.
pub gamepads: Vec<GamepadMap>,
/// The texture manager. /// The texture manager.
pub textures: TextureManager, pub textures: TextureManager,
} }
@ -246,9 +260,20 @@ impl InnerEngine {
scene, scene,
after_loop: now(&performance), after_loop: now(&performance),
keyboard: Keyboard::new(document)?, keyboard: Keyboard::new(document)?,
gamepads: vec![],
textures: TextureManager::new()?, textures: TextureManager::new()?,
}) })
} }
/// Adds a gamepad.
pub fn add_gamepad(&mut self, gamepad: &web_sys::GamepadEvent) {
let gamepad = GamepadMap::from_gamepad(gamepad.gamepad().unwrap());
let clone = gamepad.clone();
self.gamepads.push(clone);
let controlable = self.scene.controlable_mut().unwrap();
controlable.set_controls(Some(Controls::Gamepad(gamepad)));
}
} }
/// Our custom drawable trait. /// Our custom drawable trait.

View File

@ -55,6 +55,16 @@ impl Scene {
None None
} }
/// Returns the controlable.
pub fn controlable_mut(&mut self) -> Option<&mut Character> {
for character in &mut self.characters {
if character.controls().is_some() {
return Some(character);
}
}
None
}
/// Returns the right view. /// Returns the right view.
pub fn view(&self) -> Option<Bbox> { pub fn view(&self) -> Option<Bbox> {
let view = self.controlable()?.view(); let view = self.controlable()?.view();
@ -109,7 +119,7 @@ impl Scene {
c.ground_collision(); c.ground_collision();
} }
if (damage) { if damage {
c.die(); c.die();
state = State::Finished; state = State::Finished;
} }