From e1917ceb818656b9e6334abd5bce606db53155fa Mon Sep 17 00:00:00 2001 From: LLLL Colonq Date: Mon, 19 Aug 2024 16:57:00 -0400 Subject: Key rebinding --- Cargo.lock | 28 +++++++++++++ Cargo.toml | 2 + src/state.rs | 132 +++++++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 117 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ba0917..06c8b97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,6 +94,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "bimap" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" + [[package]] name = "bit_field" version = "0.10.2" @@ -366,6 +372,26 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1131,8 +1157,10 @@ dependencies = [ name = "teleia" version = "0.1.0" dependencies = [ + "bimap", "console_error_panic_hook", "console_log", + "enum-map", "getrandom", "glam", "glow", diff --git a/Cargo.toml b/Cargo.toml index 6a7fdc1..bf087ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,8 @@ tracing-wasm = "*" # trace performance in browser wasm-bindgen = "*" # interface with javascript wasm-bindgen-futures = "*" # interface with async javascript js-sys = "*" # browser APIs to interact with JS runtime (e.g. run WASM) +enum-map = "*" # fast maps with enums as keys +bimap = "*" # bijective maps [dependencies.web-sys] # common browser APIs version = "*" diff --git a/src/state.rs b/src/state.rs index 86b60bf..f4152b7 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,4 +1,6 @@ use std::collections::HashMap; +use bimap::BiHashMap; +use enum_map::{enum_map, Enum, EnumMap}; use crate::{context, framebuffer, shader, audio}; @@ -12,34 +14,56 @@ pub trait Game { fn render(&mut self, ctx: &context::Context, st: &mut State) -> Option<()>; } +#[derive(Debug, Enum, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Key { + Up, Down, Left, Right, + A, B, L, R, + Start, Select, +} +pub const KEYS: [Key; 10] = [ + Key::Up, Key::Down, Key::Left, Key::Right, + Key::A, Key::B, Key::L, Key::R, + Key::Start, Key::Select, +]; pub struct Keys { - pub up: bool, - pub down: bool, - pub left: bool, - pub right: bool, - pub a: bool, - pub b: bool, - pub l: bool, - pub r: bool, - pub start: bool, - pub select: bool, + pub pressed: EnumMap, + pub new: EnumMap, } - impl Keys { pub fn new() -> Self { Self { - up: false, - down: false, - left: false, - right: false, - a: false, - b: false, - l: false, - r: false, - start: false, - select: false, + pressed: enum_map! { + Key::Up => false, Key::Down => false, Key::Left => false, Key::Right => false, + Key::A => false, Key::B => false, Key::L => false, Key::R => false, + Key::Start => false, Key::Select => false, + }, + new: enum_map! { + Key::Up => false, Key::Down => false, Key::Left => false, Key::Right => false, + Key::A => false, Key::B => false, Key::L => false, Key::R => false, + Key::Start => false, Key::Select => false, + }, } } + pub fn up(&self) -> bool { self.pressed[Key::Up] } + pub fn down(&self) -> bool { self.pressed[Key::Down] } + pub fn left(&self) -> bool { self.pressed[Key::Left] } + pub fn right(&self) -> bool { self.pressed[Key::Right] } + pub fn a(&self) -> bool { self.pressed[Key::A] } + pub fn b(&self) -> bool { self.pressed[Key::B] } + pub fn l(&self) -> bool { self.pressed[Key::L] } + pub fn r(&self) -> bool { self.pressed[Key::R] } + pub fn start(&self) -> bool { self.pressed[Key::Start] } + pub fn select(&self) -> bool { self.pressed[Key::Select] } + pub fn new_up(&mut self) -> bool { let ret = self.new[Key::Up]; self.new[Key::Up] = false; ret } + pub fn new_down(&mut self) -> bool { let ret = self.new[Key::Down]; self.new[Key::Down] = false; ret } + pub fn new_left(&mut self) -> bool { let ret = self.new[Key::Left]; self.new[Key::Left] = false; ret } + pub fn new_right(&mut self) -> bool { let ret = self.new[Key::Right]; self.new[Key::Right] = false; ret } + pub fn new_a(&mut self) -> bool { let ret = self.new[Key::A]; self.new[Key::A] = false; ret } + pub fn new_b(&mut self) -> bool { let ret = self.new[Key::B]; self.new[Key::B] = false; ret } + pub fn new_l(&mut self) -> bool { let ret = self.new[Key::L]; self.new[Key::L] = false; ret } + pub fn new_r(&mut self) -> bool { let ret = self.new[Key::R]; self.new[Key::R] = false; ret } + pub fn new_start(&mut self) -> bool { let ret = self.new[Key::Start]; self.new[Key::Start] = false; ret } + pub fn new_select(&mut self) -> bool { let ret = self.new[Key::Select]; self.new[Key::Select] = false; ret } } pub struct PointLight { @@ -53,6 +77,8 @@ pub struct State { pub last: f64, pub tick: u64, + pub rebinding: Option, + pub keybindings: BiHashMap, pub keys: Keys, pub screen: framebuffer::Framebuffer, @@ -72,6 +98,21 @@ pub fn now(ctx: &context::Context) -> f64 { ctx.performance.now() / 1000.0 } +pub fn default_keybindings() -> BiHashMap { + BiHashMap::from_iter(vec![ + (winit::keyboard::KeyCode::KeyW, Key::Up), + (winit::keyboard::KeyCode::KeyS, Key::Down), + (winit::keyboard::KeyCode::KeyA, Key::Left), + (winit::keyboard::KeyCode::KeyD, Key::Right), + (winit::keyboard::KeyCode::Digit1, Key::A), + (winit::keyboard::KeyCode::Digit2, Key::B), + (winit::keyboard::KeyCode::KeyQ, Key::L), + (winit::keyboard::KeyCode::KeyE, Key::R), + (winit::keyboard::KeyCode::Tab, Key::Start), + (winit::keyboard::KeyCode::Space, Key::Select), + ]) +} + impl State { pub fn new(ctx: &context::Context) -> Self { let screen = framebuffer::Framebuffer::screen(ctx); @@ -90,7 +131,11 @@ impl State { acc: 0.0, last: now(ctx), tick: 0, + + rebinding: None, + keybindings: default_keybindings(), keys: Keys::new(), + screen, render_framebuffer, shader_upscale, @@ -262,18 +307,12 @@ impl State { _ctx: &context::Context, key: winit::keyboard::KeyCode, ) { - match key { - winit::keyboard::KeyCode::KeyW => self.keys.up = true, - winit::keyboard::KeyCode::KeyS => self.keys.down = true, - winit::keyboard::KeyCode::KeyA => self.keys.left = true, - winit::keyboard::KeyCode::KeyD => self.keys.right = true, - winit::keyboard::KeyCode::Digit1 => self.keys.a = true, - winit::keyboard::KeyCode::Digit2 => self.keys.b = true, - winit::keyboard::KeyCode::KeyQ => self.keys.l = true, - winit::keyboard::KeyCode::KeyE => self.keys.r = true, - winit::keyboard::KeyCode::Tab => self.keys.start = true, - winit::keyboard::KeyCode::Space => self.keys.select = true, - _ => {}, + if let Some(k) = self.rebinding { + self.keybindings.insert(key, k); + self.rebinding = None; + } else if let Some(k) = self.keybindings.get_by_left(&key) { + self.keys.pressed[*k] = true; + self.keys.new[*k] = true; } } @@ -282,21 +321,24 @@ impl State { _ctx: &context::Context, key: winit::keyboard::KeyCode, ) { - match key { - winit::keyboard::KeyCode::KeyW => self.keys.up = false, - winit::keyboard::KeyCode::KeyS => self.keys.down = false, - winit::keyboard::KeyCode::KeyA => self.keys.left = false, - winit::keyboard::KeyCode::KeyD => self.keys.right = false, - winit::keyboard::KeyCode::Digit1 => self.keys.a = false, - winit::keyboard::KeyCode::Digit2 => self.keys.b = false, - winit::keyboard::KeyCode::KeyQ => self.keys.l = false, - winit::keyboard::KeyCode::KeyE => self.keys.r = false, - winit::keyboard::KeyCode::Tab => self.keys.start = false, - winit::keyboard::KeyCode::Space => self.keys.select = false, - _ => {}, + if let Some(k) = self.keybindings.get_by_left(&key) { + self.keys.pressed[*k] = false; + } + } + + /// Return the first keybinding for the given virtual key + pub fn keybinding_for(&self, k: &Key) -> Option { + if let Some(kc) = self.keybindings.get_by_right(k) { + Some(format!("{:?}", kc)) + } else { + None } } + pub fn rebind_key(&mut self, k: &Key) { + self.rebinding = Some(*k); + } + pub fn run_update(&mut self, ctx: &context::Context, game: &mut G) where G: Game { let now = now(ctx); let diff = now - self.last; -- cgit v1.2.3