Rewrite the input system using an event based system
This commit is contained in:
parent
77053d56ad
commit
805fde2d4e
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
85
src/game.rs
85
src/game.rs
|
@ -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,16 +186,18 @@ 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);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
},
|
||||
|
@ -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);
|
||||
|
|
346
src/input.rs
346
src/input.rs
|
@ -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 {
|
||||
impl<T: Clone + Hash + Eq + PartialEq + 'static> 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 {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(v) => {
|
||||
*ev = ButtonEvent::Pressed(v.clone());
|
||||
ButtonEvent::JustPressed(b) => {
|
||||
*button = ButtonEvent::Pressed(b.clone());
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Input {
|
||||
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);
|
||||
if queue.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
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>())
|
||||
let queue = queue.unwrap();
|
||||
|
||||
// borrow checker isn't happy when I query multiple things :(
|
||||
let mut events = queue.clone();
|
||||
drop(queue);
|
||||
|
||||
while let Some(event) = events.pop_front() {
|
||||
self.update(&event, world);
|
||||
}
|
||||
|
||||
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>())
|
||||
}
|
||||
/* if let Some(queue) = world.read_events::<InputEvent>() {
|
||||
// Clone the queue, then clear it
|
||||
let mut events = queue.clone();
|
||||
drop(queue);
|
||||
|
||||
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();
|
||||
while let Some(event) = events.pop_front() {
|
||||
self.update(&event, world);
|
||||
}
|
||||
} */
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
Ok(())
|
||||
}
|
||||
}
|
57
src/main.rs
57
src/main.rs
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue