Rewrite the input system using an event based system

This commit is contained in:
SeanOMik 2023-07-21 17:54:55 -04:00
parent bdf253a597
commit ad44a96f0c
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
6 changed files with 271 additions and 381 deletions

60
Cargo.lock generated
View File

@ -1045,7 +1045,6 @@ dependencies = [
"instant",
"petgraph",
"quote",
"resources",
"syn 2.0.26",
"tobj",
"tracing",
@ -1383,7 +1382,7 @@ version = "0.3.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "221d488cd70617f1bd599ed8ceb659df2147d9393717954d82a0f5e8032a6ab1"
dependencies = [
"redox_syscall 0.3.5",
"redox_syscall",
]
[[package]]
@ -1407,17 +1406,6 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e"
[[package]]
name = "parking_lot"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core 0.8.6",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
@ -1425,21 +1413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core 0.9.8",
]
[[package]]
name = "parking_lot_core"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
dependencies = [
"cfg-if",
"instant",
"libc",
"redox_syscall 0.2.16",
"smallvec",
"winapi",
"parking_lot_core",
]
[[package]]
@ -1450,7 +1424,7 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.3.5",
"redox_syscall",
"smallvec",
"windows-targets 0.48.1",
]
@ -1564,15 +1538,6 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
[[package]]
name = "redox_syscall"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_syscall"
version = "0.3.5"
@ -1588,17 +1553,6 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157"
[[package]]
name = "resources"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42070ea13709eb92d2977b48c7d3bd44866fa328e14248f8d1f00d6ea14d5066"
dependencies = [
"downcast-rs",
"fxhash",
"parking_lot 0.11.2",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
@ -2161,7 +2115,7 @@ dependencies = [
"js-sys",
"log",
"naga",
"parking_lot 0.12.1",
"parking_lot",
"profiling",
"raw-window-handle",
"smallvec",
@ -2187,7 +2141,7 @@ dependencies = [
"fxhash",
"log",
"naga",
"parking_lot 0.12.1",
"parking_lot",
"profiling",
"raw-window-handle",
"smallvec",
@ -2226,7 +2180,7 @@ dependencies = [
"metal",
"naga",
"objc",
"parking_lot 0.12.1",
"parking_lot",
"profiling",
"range-alloc",
"raw-window-handle",
@ -2459,7 +2413,7 @@ dependencies = [
"orbclient",
"percent-encoding",
"raw-window-handle",
"redox_syscall 0.3.5",
"redox_syscall",
"sctk-adwaita",
"smithay-client-toolkit",
"wasm-bindgen",

View File

@ -24,7 +24,6 @@ async-trait = "0.1.65"
hecs = "0.10.3"
glam = { version = "0.24.0", features = ["bytemuck"] }
petgraph = "0.6.3"
resources = "1.1.0"
gilrs-core = "0.5.6"
syn = "2.0.26"
quote = "1.0.29"

View File

@ -1,16 +1,18 @@
use std::{any::{TypeId, Any}, collections::{HashMap, HashSet, VecDeque}, ops::{Deref, DerefMut}};
use std::{any::{TypeId, Any}, collections::{HashMap, HashSet, VecDeque}, ops::{Deref, DerefMut}, cell::{RefCell, Ref, RefMut}};
use tracing::debug;
use super::resources::{Resource, Events};
pub struct World {
inner: hecs::World,
resources: HashMap<TypeId, Box<dyn Resource>>,
resources: HashMap<TypeId, Box<RefCell<dyn Resource>>>,
updated_resources: HashSet<TypeId>,
// a boolean that flip flops to clear events every other frame
events_flipflop: bool,
events: HashMap<TypeId, Box<dyn Resource>>,
event_write_queue: HashMap<TypeId, Box<dyn Resource>>,//VecDeque<(TypeId, Box<dyn Resource>)>,
events: HashMap<TypeId, Box<RefCell<dyn Resource>>>,
event_write_queue: HashMap<TypeId, Box<RefCell<dyn Resource>>>,//VecDeque<(TypeId, Box<dyn Resource>)>,
}
impl Deref for World {
@ -47,16 +49,16 @@ impl World {
/// Attempts to query a resource, or will create it when its not found.
///
/// The resource will be created by a function passed in `default`.
pub fn query_or_insert_res<R>(&mut self, default: impl Fn() -> Box<dyn Resource + 'static>) -> &mut R
pub fn query_or_insert_res<R>(&mut self, default: impl Fn() -> Box<RefCell<dyn Resource + 'static>>) -> RefMut<R>
where
R: Resource,
{
let type_id = TypeId::of::<R>();
self.resources.entry(type_id)
let r = self.resources.entry(type_id)
.or_insert_with(default)
.as_any_mut()
.downcast_mut()
.unwrap()
.borrow_mut();
RefMut::map(r, |r| r.as_any_mut().downcast_mut::<R>().unwrap())
}
/// Insert a resource into the World. You can only have one resource of the same type.
@ -68,7 +70,7 @@ impl World {
R: Resource
{
let type_id = res.type_id();
self.resources.insert(type_id, Box::new(res));
self.resources.insert(type_id, Box::new(RefCell::new(res)));
self.updated_resources.insert(type_id);
}
@ -90,22 +92,23 @@ impl World {
E: Clone + Send + Sync + 'static
{
// the compiler wants me to explicit right here for some reason
let default = || Box::new(Events::<E>::new()) as Box<(dyn Resource + 'static)>;
let default = || Box::new(RefCell::new(Events::<E>::new())) as Box<RefCell<(dyn Resource + 'static)>>;
// Get, or create, a list of events of this type
let type_id = TypeId::of::<E>();
let events: &mut Events<E> = self.event_write_queue.entry(type_id)
let type_id = event.type_id();
let events = self.event_write_queue.entry(type_id)
.or_insert_with(default)
.as_any_mut()
.downcast_mut()
.unwrap();
.borrow_mut();
// downcast resource as an events storage
let mut events: RefMut<Events<E>> = RefMut::map(events, |e| e.as_any_mut().downcast_mut().unwrap());
events.push_back(event);
}
/// Clear events, this should happen at the start of every tick since events are cloned
/// before being given to the reader.
pub fn clear_events(&mut self) {
pub fn update_events(&mut self) {
self.events.clear();
// get all keys of events
@ -113,37 +116,58 @@ impl World {
// remove all elements from self.event_write_queue and insert them to events
for k in keys.into_iter() {
self.events.insert(k, self.event_write_queue.remove(&k).unwrap());
let v = self.event_write_queue.remove(&k).unwrap();
self.events.insert(k, v);
}
}
pub fn read_events<E>(&self) -> Option<&Events<E>>
pub fn read_events<E>(&self) -> Option<Ref<Events<E>>>
where
E: Clone + Send + Sync + 'static
{
self.events.get(&TypeId::of::<E>())
.map(|r| r.as_any().downcast_ref::<Events<E>>())
.flatten()
if let Some(event ) = self.events.get(&TypeId::of::<E>()) {
//.or_else(|| self.event_write_queue.get(&TypeId::of::<E>())) {
let eref = event.borrow();
Some(Ref::map(eref, |x| x.as_any().downcast_ref::<Events<E>>().unwrap()))
} else {
None
}
/* if let Some(event) = self.events.get(&TypeId::of::<E>()) {
let eref = event.borrow();
Some(Ref::map(eref, |x| x.as_any().downcast_ref::<Events<E>>().unwrap()))
} else if let Some(event) = self.events.get(&TypeId::of::<E>()) {
None
} */
/* self.events.get(&TypeId::of::<E>())
//.map(|r| r.borrow().as_any().downcast_ref::<Events<E>>())
.map(|r| r.borrow().as_any().do)
.flatten() */
}
/// Query a resource.
///
/// This is O(1), resources are stored in HashMaps.
pub fn query_res<R>(&self) -> Option<&R>
pub fn query_res<R>(&self) -> Option<Ref<R>>
where
R: Resource
{
self.resources
.get(&TypeId::of::<R>())
.map(|r| r.as_any().downcast_ref())
.flatten()
.map(|r| {
let r = r.borrow();
Ref::map(r, |r| r.as_any().downcast_ref().unwrap())
})
}
/// Query a resource mutably.
///
/// This will mark the resource as changed, even if it actually wasn't modified when mutably borrowed.
/// This is O(1), resources are stored in HashMaps.
pub fn query_res_mut<R>(&mut self) -> Option<&mut R>
pub fn query_res_mut<R>(&mut self) -> Option<RefMut<R>>
where
R: Resource
{
@ -153,8 +177,9 @@ impl World {
// update resource
self.updated_resources.insert(TypeId::of::<R>());
r.as_any_mut().downcast_mut()
let r = r.borrow_mut();
RefMut::map(r, |r| r.as_any_mut().downcast_mut::<R>().unwrap())
})
.flatten()
}
}

View File

@ -4,7 +4,6 @@ use async_std::{task::block_on, sync::Mutex};
//use hecs::World;
use instant::Instant;
use resources::{Resources, Resource};
use tracing::{metadata::LevelFilter, info, debug, warn, error};
use tracing_subscriber::{
layer::{Layer, SubscriberExt},
@ -14,11 +13,10 @@ use tracing_subscriber::{
use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, DeviceEvent}, event_loop::{EventLoop, ControlFlow}};
use crate::{render::{renderer::{Renderer, BasicRenderer}, render_job::RenderJob}, input_event::InputEvent, ecs::{components::{mesh::MeshComponent, transform::TransformComponent}, SimpleSystem, SystemDispatcher, world::World, resources::{WindowState, Events}}, input::Input};
use crate::{render::{renderer::{Renderer, BasicRenderer}, render_job::RenderJob}, input_event::InputEvent, ecs::{components::{mesh::MeshComponent, transform::TransformComponent}, SimpleSystem, SystemDispatcher, world::World, resources::{WindowState, Events}}, input::InputEventUpdater};
pub struct Controls<'a> {
pub world: &'a mut World,
pub resources: &'a mut Resources,
}
struct TickCounter {
@ -81,7 +79,6 @@ struct GameLoop {
renderer: Box<dyn Renderer>,
world: Arc<Mutex<World>>,
resources: Arc<Mutex<Resources>>,
/// higher priority systems
engine_sys_dispatcher: SystemDispatcher,
user_sys_dispatcher: SystemDispatcher,
@ -89,13 +86,12 @@ struct GameLoop {
}
impl GameLoop {
pub async fn new(window: Arc<Window>, world: Arc<Mutex<World>>, resources: Arc<Mutex<Resources>>, user_systems: SystemDispatcher) -> GameLoop {
pub async fn new(window: Arc<Window>, world: Arc<Mutex<World>>, user_systems: SystemDispatcher) -> GameLoop {
Self {
window: Arc::clone(&window),
renderer: Box::new(BasicRenderer::create_with_window(window).await),
world,
resources,
engine_sys_dispatcher: SystemDispatcher::new(),
user_sys_dispatcher: user_systems,
fps_counter: TickCounter::new(),
@ -112,13 +108,9 @@ impl GameLoop {
async fn update(&mut self) {
let mut world = self.world.lock().await;
let mut resources = self.resources.lock().await;
world.clear_events();
let mut controls = Controls {
world: &mut world,
resources: &mut resources
};
if let Err(e) = self.engine_sys_dispatcher.execute_mut(&mut controls) {
@ -149,16 +141,8 @@ impl GameLoop {
// TODO: Create system for this? or maybe merge into input system, idk
InputEvent::CursorEntered { .. } => {
let mut world = self.world.lock().await;
let state = match world.query_res_mut::<WindowState>() {
Some(i) => i,
None => {
world.insert_resource(WindowState::new());
// must succeed since it was just added
world.query_res_mut::<WindowState>().unwrap()
}
};
let mut state = world.query_or_insert_res::<WindowState>(|| Box::new(RefCell::new(WindowState::new())));
state.is_cursor_inside_window = true;
None
@ -166,16 +150,8 @@ impl GameLoop {
InputEvent::CursorLeft { .. } => {
let mut world = self.world.lock().await;
let state = match world.query_res_mut::<WindowState>() {
Some(i) => i,
None => {
world.insert_resource(WindowState::new());
// must succeed since it was just added
world.query_res_mut::<WindowState>().unwrap()
}
};
let mut state = world.query_or_insert_res::<WindowState>(|| Box::new(RefCell::new(WindowState::new())));
state.is_cursor_inside_window = false;
None
@ -210,15 +186,17 @@ impl GameLoop {
let mut world = self.world.lock().await;
// make sure that the mouse is inside the window and the mouse has focus before reporting mouse motion
if let Some(window_state) = world.query_res::<WindowState>() {
if window_state.is_focused && window_state.is_cursor_inside_window {
let trigger = match world.query_res::<WindowState>() {
Some(window_state) if window_state.is_focused && window_state.is_cursor_inside_window => true,
_ => false,
};
let event_queue = world.query_or_insert_res::<Events<InputEvent>>
(|| Box::new(Events::<InputEvent>::new()));
if trigger {
let mut event_queue = world.query_or_insert_res::<Events<InputEvent>>
(|| Box::new(RefCell::new(Events::<InputEvent>::new())));
let input_event = InputEvent::MouseMotion { device_id, delta, };
event_queue.push_back(input_event);
}
let input_event = InputEvent::MouseMotion { device_id, delta, };
event_queue.push_back(input_event);
}
},
_ => {}
@ -236,17 +214,6 @@ impl GameLoop {
{
let mut world = self.world.lock().await;
world.trigger_event(input_event.clone());
/* let event_queue = match world.query_res_mut::<Events<InputEvent>>() {
Some(i) => i,
None => {
world.insert_resource(VecDeque::<InputEvent>::new());
// must succeed since it was just added
world.query_res_mut::<Events<InputEvent>>().unwrap()
}
};
event_queue.push_back(input_event.clone()); */
}
if let Some(new_control) = self.input_update(&input_event).await {
@ -270,16 +237,8 @@ impl GameLoop {
WindowEvent::Focused(is_focused) => {
let mut world = self.world.lock().await;
let state = match world.query_res_mut::<WindowState>() {
Some(s) => s,
None => {
world.insert_resource(WindowState::new());
// must succeed since it was just added
world.query_res_mut::<WindowState>().unwrap()
}
};
let mut state = world.query_or_insert_res::<WindowState>(|| Box::new(RefCell::new(WindowState::new())));
state.is_focused = *is_focused;
},
@ -300,6 +259,7 @@ impl GameLoop {
let mut world = self.world.lock().await;
self.renderer.as_mut().prepare(&mut world).await;
world.clear_updated_resources();
world.update_events();
drop(world);
match self.renderer.as_mut().render().await {
@ -323,7 +283,6 @@ impl GameLoop {
pub struct Game {
world: Option<Arc<Mutex<World>>>,
resources: Option<Arc<Mutex<Resources>>>,
system_dispatcher: Option<SystemDispatcher>
}
@ -331,7 +290,6 @@ impl Default for Game {
fn default() -> Self {
Self {
world: None,
resources: Some(Arc::new(Mutex::new(Resources::new()))),
system_dispatcher: Some(SystemDispatcher::new()),
}
}
@ -382,30 +340,15 @@ impl Game {
self
}
pub async fn with_res<T>(&mut self, r: T) -> &mut Self
where
T: Resource
{
let resources = self.resources.as_mut().unwrap();
let mut resources = resources.lock().await;
resources.insert(r);
drop(resources);
self
}
pub async fn run(&mut self) {
let world = self.world.take().expect("ECS World was never given to Game!");
let resources = self.resources.take().unwrap();
let event_loop = EventLoop::new();
let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap());
let systems = self.system_dispatcher.take().unwrap();
let mut g_loop = GameLoop::new(Arc::clone(&window), world, resources, systems).await;
let mut g_loop = GameLoop::new(Arc::clone(&window), world, systems).await;
event_loop.run(move |event, _, control_flow| {
g_loop.run_sync(event, control_flow);

View File

@ -1,4 +1,4 @@
use std::{any::{Any, TypeId}, collections::{HashMap, hash_map::DefaultHasher, VecDeque}, hash::{Hash, Hasher}, sync::{Arc, Mutex}};
use std::{any::{Any, TypeId}, collections::{HashMap, hash_map::DefaultHasher, VecDeque, HashSet}, hash::{Hash, Hasher}, sync::{Arc, Mutex}, cell::RefCell};
use gilrs_core::Gilrs;
use glam::Vec2;
@ -9,45 +9,24 @@ use crate::{ecs::{SimpleSystem, resources::{Resource, Events}, world::World}, in
pub type KeyCode = winit::event::VirtualKeyCode;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ButtonEvent<T: Hash + 'static> {
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub enum ButtonEvent<T: Clone + Hash + Eq + PartialEq + 'static> {
Pressed(T),
Released(T),
JustPressed(T),
}
pub struct InputSystem;
impl InputSystem {
pub fn new() -> Self {
Self {}
}
}
impl SimpleSystem for InputSystem {
fn execute_mut(&mut self, controls: &mut crate::game::Controls) -> anyhow::Result<()> {
let world = &mut controls.world;
if let Some(queue) = world.query_res_mut::<Events<InputEvent>>() {
// Clone the queue, then clear it
let mut queue = {
let a = queue.clone();
queue.clear();
a
};
if let Some(input) = world.query_res_mut::<Input>() {
// clear input before processing the queue
input.clear();
// process the all events that happened this tick
while let Some(event) = queue.pop_front() {
input.update(&event, world);
}
}
impl<T: Clone + Hash + Eq + PartialEq + 'static> ButtonEvent<T> {
fn take_val(self) -> T {
match self {
ButtonEvent::Pressed(t) => t,
ButtonEvent::JustPressed(t) => t,
ButtonEvent::Released(t) => t,
}
}
Ok(())
fn clone_val(&self) -> T {
self.clone().take_val()
}
}
@ -121,10 +100,28 @@ pub struct Touches {
pub touches: Vec<Touch>,
}
impl Resource for Touches {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl Touches {
pub fn new() -> Self {
Self {
touches: Vec::new()
}
}
}
/// A mouse button event
///
/// Translated `WindowEvent::MouseButton` from `winit` crate
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum MouseButton {
Left,
Right,
@ -149,14 +146,13 @@ pub struct CursorEnteredWindow;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CursorLeftWindow;
pub struct Input {
gilrs: Option<Arc<Mutex<Gilrs>>>, // TODO
// the key is a u64. This is a hash of the value stored inside of the Box
button_events: HashMap<u64, Box<dyn Any + Send + Sync>>,
typed_events: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
pub struct InputButtons<T: Clone + Hash + Eq + PartialEq + 'static> {
// 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 Resource for Input {
impl<T: Sync + Send + Clone + Hash + Eq + PartialEq + 'static> Resource for InputButtons<T> {
fn as_any(&self) -> &dyn Any {
self
}
@ -166,28 +162,108 @@ impl Resource for Input {
}
}
/// helper function for converting
#[inline(always)]
fn button_event_retain<E>(val: &mut Box<dyn Any + Send + Sync>) -> bool
where
E: Clone + Hash + 'static,
{
if let Some(ev) = val.downcast_mut::<ButtonEvent<E>>() {
match ev {
ButtonEvent::Released(_) => {
return false;
},
ButtonEvent::JustPressed(v) => {
*ev = ButtonEvent::Pressed(v.clone());
},
_ => {}
impl<T: Clone + Hash + Eq + PartialEq + 'static> InputButtons<T> {
pub fn new() -> Self {
Self {
button_events: HashMap::new(),
}
}
true
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 {
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
}
}
}
impl Input {
trait InputStorage {
fn update_just_pressed(&mut self);
}
impl<T: Clone + Hash + Eq + PartialEq + 'static> InputStorage for InputButtons<T> {
fn update_just_pressed(&mut self) {
/* for (hash, button) in self.button_events.iter_mut() {
/* if let ButtonEvent::JustPressed(b) = button {
*button = ButtonEvent::Pressed(b.clone());
} */
match button {
ButtonEvent::Pressed(_) => todo!(),
ButtonEvent::Released(b) => {
return false;
},
ButtonEvent::JustPressed(b) => {
*button = ButtonEvent::Pressed(b.clone());
},
}
} */
self.button_events.retain(|_hash, button| {
match button {
// remove released, no need to keep those around.
ButtonEvent::Released(_) => {
return false;
},
ButtonEvent::JustPressed(b) => {
*button = ButtonEvent::Pressed(b.clone());
},
_ => {},
}
true
});
}
}
pub struct InputEventUpdater {
gilrs: Option<Arc<Mutex<Gilrs>>>, // TODO
}
impl InputEventUpdater {
pub(crate) fn new() -> Self {
let gilrs = match Gilrs::new() {
Ok(g) => Some(Arc::new(Mutex::new(g))),
@ -200,38 +276,6 @@ impl Input {
Self {
gilrs,
button_events: HashMap::new(),
typed_events: HashMap::new(),
}
}
pub fn clear(&mut self) {
// Convert JustPressed inputs to Pressed, and remove Released events
self.button_events.retain(|_, v| {
if !button_event_retain::<KeyCode>(v)
|| !button_event_retain::<MouseButton>(v)
{
return false;
}
true
});
self.typed_events.retain(|_, v| {
if v.downcast_ref::<MouseMotion>().is_some()
|| v.downcast_ref::<MouseExact>().is_some()
|| v.downcast_ref::<CursorEnteredWindow>().is_some()
|| v.downcast_ref::<CursorLeftWindow>().is_some()
|| v.downcast_ref::<MouseScroll>().is_some()
{
return false;
}
true
});
if let Some(touches) = self.get_event_mut::<Touches>() {
touches.touches.clear();
}
}
@ -239,7 +283,9 @@ impl Input {
match event {
InputEvent::KeyboardInput { input, .. } => {
if let Some(code) = input.virtual_keycode {
self.create_button_event(code, input.state);
let mut e = world.query_or_insert_res::<InputButtons<KeyCode>>
(|| Box::new(RefCell::new(InputButtons::<KeyCode>::new())));
e.add_input_from_winit(code, input.state);
}
},
InputEvent::MouseMotion { delta, .. } => {
@ -247,22 +293,22 @@ impl Input {
delta: Vec2::new(delta.0 as f32, delta.1 as f32)
};
self.typed_events.insert(delta.type_id(), Box::new(delta));
world.trigger_event(delta);
},
InputEvent::CursorMoved { position, .. } => {
let exact = MouseExact {
pos: Vec2::new(position.x as f32, position.y as f32)
};
self.typed_events.insert(exact.type_id(), Box::new(exact));
world.trigger_event(exact);
},
InputEvent::CursorEntered { .. } => {
let event = CursorEnteredWindow {};
self.typed_events.insert(event.type_id(), Box::new(event));
world.trigger_event(event);
},
InputEvent::CursorLeft { .. } => {
let event = CursorLeftWindow {};
self.typed_events.insert(event.type_id(), Box::new(event));
world.trigger_event(event);
},
InputEvent::MouseWheel { delta, .. } => {
let event = match delta {
@ -274,17 +320,21 @@ impl Input {
},
};
self.typed_events.insert(event.type_id(), Box::new(event));
world.trigger_event(event);
}, //MouseButton
InputEvent::MouseInput { button, state, .. } => {
let button = match button {
let button_event = match button {
winit::event::MouseButton::Left => MouseButton::Left,
winit::event::MouseButton::Right => MouseButton::Right,
winit::event::MouseButton::Middle => MouseButton::Middle,
winit::event::MouseButton::Other(v) => MouseButton::Other(*v),
};
self.create_button_event(button, *state);
world.trigger_event(button_event.clone());
let mut e = world.query_or_insert_res::<InputButtons<MouseButton>>
(|| Box::new(RefCell::new(InputButtons::<MouseButton>::new())));
e.add_input_from_winit(button_event, state.clone());
},
InputEvent::Touch(t) => {
let touch = Touch {
@ -297,17 +347,8 @@ impl Input {
finger_id: t.id,
};
let touches = match self.get_event_mut::<Touches>() {
Some(t) => t,
None => {
let t = Touches {
touches: Vec::new(),
};
self.typed_events.insert(t.type_id(), Box::new(t));
self.get_event_mut::<Touches>().unwrap()
}
};
let mut touches = world.query_or_insert_res::<Touches>
(|| Box::new(RefCell::new(Touches::new())));
touches.touches.push(touch);
},
@ -316,89 +357,38 @@ impl Input {
false
}
}
fn create_button_event<B>(&mut self, button: B, state: ElementState)
where
B: Hash + PartialEq + Clone + Copy + Sync + Send + 'static
{
// Get a hash of the button
let mut hasher = DefaultHasher::new();
button.hash(&mut hasher);
let code_hash = hasher.finish();
impl SimpleSystem for InputEventUpdater {
fn execute_mut(&mut self, controls: &mut crate::game::Controls) -> anyhow::Result<()> {
let world = &mut controls.world;
// convert state
let buttonev = Box::new(match state {
ElementState::Pressed if self.is_pressed(button) => ButtonEvent::Pressed(button),
ElementState::Pressed => ButtonEvent::JustPressed(button),
ElementState::Released => ButtonEvent::Released(button),
});
let queue = world.read_events::<InputEvent>();
self.button_events.insert(code_hash, buttonev);
}
pub fn get_event<E: 'static>(&self) -> Option<&E> {
self.typed_events.get(&TypeId::of::<E>())
.and_then(|e| e.as_ref()
.downcast_ref::<E>())
}
pub(crate) fn get_event_mut<E: 'static>(&mut self) -> Option<&mut E> {
self.typed_events.get_mut(&TypeId::of::<E>())
.and_then(|e| e.as_mut()
.downcast_mut::<E>())
}
pub fn was_just_pressed<T>(&self, code: T) -> bool
where
T: Hash + PartialEq + Clone + 'static
{
// get a hash of the key code
let mut hasher = DefaultHasher::new();
code.hash(&mut hasher);
let inner_hash = hasher.finish();
if let Some(e) = self.button_events.get(&inner_hash) {
if let Some(ev) = e.downcast_ref::<ButtonEvent<T>>() {
match ev {
ButtonEvent::JustPressed(v) => {
if v.clone() == code {
return true;
}
},
_ => {
return false;
}
}
}
if queue.is_none() {
return Ok(());
}
false
}
let queue = queue.unwrap();
pub fn is_pressed<T>(&self, code: T) -> bool
where
T: Hash + PartialEq + Clone + 'static
{
// get a hash of the key code
let mut hasher = DefaultHasher::new();
code.hash(&mut hasher);
let inner_hash = hasher.finish();
// borrow checker isn't happy when I query multiple things :(
let mut events = queue.clone();
drop(queue);
if let Some(e) = self.button_events.get(&inner_hash) {
if let Some(ev) = e.downcast_ref::<ButtonEvent<T>>() {
match ev {
ButtonEvent::Pressed(v) | ButtonEvent::JustPressed(v) => {
if v.clone() == code {
return true;
}
},
_ => {
return false;
}
}
}
while let Some(event) = events.pop_front() {
self.update(&event, world);
}
false
/* if let Some(queue) = world.read_events::<InputEvent>() {
// Clone the queue, then clear it
let mut events = queue.clone();
drop(queue);
while let Some(event) = events.pop_front() {
self.update(&event, world);
}
} */
Ok(())
}
}

View File

@ -6,14 +6,17 @@ mod ecs;
mod math;
mod input;
use std::cell::Ref;
use ecs::components::mesh::MeshComponent;
use ecs::components::transform::TransformComponent;
use game::Game;
use input_event::InputEvent;
use tracing::debug;
use crate::ecs::world::World;
use crate::input::{Input, KeyCode, InputSystem, MouseMotion, MouseExact, CursorEnteredWindow, MouseScroll, CursorLeftWindow, MouseButton};
use crate::input::{InputEventUpdater, KeyCode, MouseMotion, MouseExact, CursorEnteredWindow, MouseScroll, CursorLeftWindow, MouseButton, InputButtons};
use crate::render::material::Material;
use crate::render::texture::Texture;
use crate::ecs::components::camera::CameraComponent;
@ -86,64 +89,40 @@ async fn main() {
camera.transform.translation += glam::Vec3::new(0.0, 0.0, 2.0);
//camera.transform.rotate_y(Angle::Degrees(-25.0));
camera.transform.rotate_z(Angle::Degrees(-90.0));
world.insert_resource(Input::new());
world.spawn((camera,));
let jiggle_system = |world: &mut World| -> anyhow::Result<()> {
let input: &Input = world.query_res().unwrap();
//let input: &InputEventUpdater = world.query_res().unwrap();
let keys = world.query_res();
if keys.is_none() {
return Ok(());
}
let keys: Ref<InputButtons<KeyCode>> = keys.unwrap();
let speed = 0.001;
let mut dir_x = 0.0;
let mut dir_y = 0.0;
if input.is_pressed(KeyCode::A) {
if keys.is_pressed(KeyCode::A) {
dir_x -= speed;
}
if input.is_pressed(KeyCode::D) {
if keys.is_pressed(KeyCode::D) {
dir_x += speed;
}
if input.is_pressed(KeyCode::S) {
if keys.is_pressed(KeyCode::S) {
dir_y -= speed;
}
if input.is_pressed(KeyCode::W) {
if keys.is_pressed(KeyCode::W) {
dir_y += speed;
}
if input.is_pressed(MouseButton::Left) {
debug!("left mouse button!");
}
if input.is_pressed(MouseButton::Middle) {
debug!("middle mouse button!");
}
if input.is_pressed(MouseButton::Right) {
debug!("right mouse button!");
}
if let Some(motion) = input.get_event::<MouseMotion>() {
debug!("delta: {}", motion.delta);
}
if let Some(exact) = input.get_event::<MouseExact>() {
debug!("exact pos: {:?}", exact);
}
if let Some(scroll) = input.get_event::<MouseScroll>() {
debug!("scrolled: {:?}", scroll);
}
if input.get_event::<CursorEnteredWindow>().is_some() {
debug!("cursor entered window!");
}
if input.get_event::<CursorLeftWindow>().is_some() {
debug!("cursor left window!");
}
drop(keys);
for (_eid, (transform, )) in world.query_mut::<(&mut TransformComponent,)>() {
let t = &mut transform.transform;
@ -161,7 +140,7 @@ async fn main() {
Game::initialize().await
.with_world(world)
.with_system("input", InputEventUpdater::new(), &[])
.with_system("jiggle", jiggle_system, &[])
.with_system("input_system", InputSystem::new(), &[])
.run().await;
}