lyra-engine/lyra-game/src/input/buttons.rs

103 lines
3.2 KiB
Rust

use std::{hash::{Hash, Hasher}, collections::{HashMap, hash_map::DefaultHasher}};
use winit::event::ElementState;
//pub trait Button : Clone + Hash + Eq + PartialEq + 'static {}
/* pub trait Button {}
impl<T: Clone + Hash + Eq + PartialEq + 'static> Button for T {} */
pub trait Button = Clone + Hash + Eq + PartialEq + 'static;
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub enum ButtonEvent<T: Button> {
Pressed(T),
Released(T),
JustPressed(T),
}
impl<T: Button> ButtonEvent<T> {
fn take_val(self) -> T {
match self {
ButtonEvent::Pressed(t) => t,
ButtonEvent::JustPressed(t) => t,
ButtonEvent::Released(t) => t,
}
}
fn clone_val(&self) -> T {
self.clone().take_val()
}
}
#[derive(Clone)]
pub struct InputButtons<T: Button> {
// the u64 as the key is the hashed value of T. this makes it easier to
// search for a button and see its state
button_events: HashMap<u64, ButtonEvent<T>>,
}
impl<T: Button> Default for InputButtons<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Button> InputButtons<T> {
pub fn new() -> Self {
Self {
button_events: HashMap::new(),
}
}
fn get_button_hash(button: &T) -> u64 {
let mut hasher = DefaultHasher::new();
button.hash(&mut hasher);
hasher.finish()
}
/// Add a button event to this input type
pub fn add_input(&mut self, button: ButtonEvent<T>) {
let hash = Self::get_button_hash(&button.clone_val());
self.button_events.insert(hash, button);
}
pub(crate) fn add_input_from_winit(&mut self, button: T, state: ElementState) {
let event = match state {
// TODO: there is a pause between pressed events of a key when holding down, so it stays in a just pressed state for too long
// When a button is held down, this would change a just pressed button into a pressed button.
ElementState::Pressed if self.is_pressed(button.clone()) => ButtonEvent::Pressed(button),
ElementState::Pressed => ButtonEvent::JustPressed(button),
ElementState::Released => ButtonEvent::Released(button),
};
self.add_input(event);
}
/// Returns true if the button is pressed (or was just pressed)
pub fn is_pressed(&self, button: T) -> bool
{
let hash = Self::get_button_hash(&button);
match self.button_events.get(&hash) {
Some(button_event) => match button_event {
// this if statement should always be true, but just in case ;)
ButtonEvent::Pressed(b) | ButtonEvent::JustPressed(b) if button == *b => true,
_ => false,
},
None => false
}
}
/// Returns true if the button was just pressed this tick
pub fn was_just_pressed(&self, button: T) -> bool {
let hash = Self::get_button_hash(&button);
match self.button_events.get(&hash) {
Some(button_event) => match button_event {
// this if statement should always be true, but just in case ;)
ButtonEvent::JustPressed(b) if button == *b => true,
_ => false,
},
None => false
}
}
}