Add resource system, early input system, custom hecs world wrapper
This commit is contained in:
parent
f7a455997d
commit
d25ecf0e00
File diff suppressed because it is too large
Load Diff
|
@ -21,7 +21,8 @@ tobj = { version = "3.2.1", features = [
|
|||
]}
|
||||
instant = "0.1"
|
||||
async-trait = "0.1.65"
|
||||
specs = { version = "0.18.0", features = [ "derive" ] }
|
||||
hecs = "0.10.3"
|
||||
glam = { version = "0.24.0", features = ["bytemuck"] }
|
||||
petgraph = "0.6.3"
|
||||
resources = "1.1.0"
|
||||
gilrs-core = "0.5.6"
|
||||
|
|
|
@ -11,6 +11,7 @@ mkShell rec {
|
|||
valgrind
|
||||
heaptrack
|
||||
mold
|
||||
udev
|
||||
];
|
||||
buildInputs = [
|
||||
udev alsa-lib vulkan-loader
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
pub struct Controls {
|
||||
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
use specs::{Component, DenseVecStorage};
|
||||
|
||||
use crate::render::{vertex::Vertex, mesh::Mesh, material::Material};
|
||||
|
||||
#[derive(Component, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct MeshComponent {
|
||||
pub mesh: Mesh,
|
||||
pub material: Material,
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use specs::{Component, DenseVecStorage};
|
||||
|
||||
use crate::math::Transform;
|
||||
|
||||
#[derive(Component, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct TransformComponent {
|
||||
pub transform: Transform,
|
||||
}
|
||||
|
|
|
@ -1,27 +1,31 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use hecs::World;
|
||||
use petgraph::{prelude::StableDiGraph, stable_graph::NodeIndex, visit::Topo};
|
||||
use tracing::warn;
|
||||
|
||||
use crate::game::Controls;
|
||||
|
||||
pub mod components;
|
||||
pub mod world;
|
||||
|
||||
use world::World;
|
||||
|
||||
/// A trait that represents a simple system
|
||||
pub trait SimpleSystem {
|
||||
fn setup(&mut self, world: &mut World) -> anyhow::Result<()> {
|
||||
fn setup(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// todo: make async?
|
||||
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()>;
|
||||
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()>;
|
||||
}
|
||||
|
||||
impl<S> SimpleSystem for S
|
||||
where S: FnMut(&mut World) -> anyhow::Result<()>
|
||||
{
|
||||
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
|
||||
self(world)
|
||||
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
|
||||
self(controls.world)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,9 +44,9 @@ impl BatchedSystem {
|
|||
}
|
||||
|
||||
impl SimpleSystem for BatchedSystem {
|
||||
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
|
||||
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
|
||||
for system in self.systems.iter_mut() {
|
||||
system.execute_mut(world)?;
|
||||
system.execute_mut(controls)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -111,13 +115,13 @@ impl SystemDispatcher {
|
|||
true
|
||||
}
|
||||
|
||||
pub(crate) fn execute_systems(&mut self, world: &mut World) {
|
||||
pub(crate) fn execute_systems(&mut self, controls: &mut Controls) {
|
||||
let mut topo = Topo::new(&self.graph);
|
||||
|
||||
while let Some(nx) = topo.next(&self.graph) {
|
||||
let node = self.graph.node_weight_mut(nx).unwrap();
|
||||
|
||||
match node.system.execute_mut(world) {
|
||||
match node.system.execute_mut(controls) {
|
||||
Ok(()) => {},
|
||||
Err(e) => {
|
||||
warn!("System execution of {} resulted in an error! '{}'.", node.name, e);
|
||||
|
@ -133,8 +137,8 @@ impl SystemDispatcher {
|
|||
}
|
||||
|
||||
impl SimpleSystem for SystemDispatcher {
|
||||
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
|
||||
self.execute_systems(world);
|
||||
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
|
||||
self.execute_systems(controls);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
use std::{any::{TypeId, Any}, collections::{HashMap, HashSet, VecDeque}, ops::{Deref, DerefMut}};
|
||||
|
||||
use winit::event::WindowEvent;
|
||||
|
||||
pub trait Resource: Send + Sync + 'static {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
}
|
||||
|
||||
impl Resource for WindowEvent<'static> {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sync + Send + 'static> Resource for VecDeque<T> {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct World {
|
||||
inner: hecs::World,
|
||||
resources: HashMap<TypeId, Box<dyn Resource>>,
|
||||
updated_resources: HashSet<TypeId>,
|
||||
}
|
||||
|
||||
impl Deref for World {
|
||||
type Target = hecs::World;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for World {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl World {
|
||||
pub fn new() -> Self {
|
||||
Self::from_hecs(hecs::World::new())
|
||||
}
|
||||
|
||||
pub fn from_hecs(hecs_world: hecs::World) -> Self {
|
||||
Self {
|
||||
inner: hecs_world,
|
||||
resources: HashMap::new(),
|
||||
updated_resources: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert a resource into the World. You can only have one resource of the same type.
|
||||
/// If you attempt to add another resource of the same type, it will be replaced.
|
||||
///
|
||||
/// This will also mark the resource as updated in this frame.
|
||||
pub fn insert_resource<R>(&mut self, res: R)
|
||||
where
|
||||
R: Resource
|
||||
{
|
||||
let type_id = res.type_id();
|
||||
self.resources.insert(type_id, Box::new(res));
|
||||
self.updated_resources.insert(type_id);
|
||||
}
|
||||
|
||||
/// Checks if a resource was updated this frame.
|
||||
pub fn was_res_updated<R>(&self) -> bool
|
||||
where
|
||||
R: Resource
|
||||
{
|
||||
self.updated_resources.contains(&TypeId::of::<R>())
|
||||
}
|
||||
|
||||
pub(crate) fn clear_updated_resources(&mut self) {
|
||||
self.updated_resources.clear();
|
||||
}
|
||||
|
||||
/// Query a resource.
|
||||
///
|
||||
/// This is O(1), resources are stored in HashMaps.
|
||||
pub fn query_res<R>(&self) -> Option<&R>
|
||||
where
|
||||
R: Resource
|
||||
{
|
||||
self.resources
|
||||
.get(&TypeId::of::<R>())
|
||||
.map(|r| r.as_any().downcast_ref())
|
||||
.flatten()
|
||||
}
|
||||
|
||||
/// 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>
|
||||
where
|
||||
R: Resource
|
||||
{
|
||||
self.resources
|
||||
.get_mut(&TypeId::of::<R>())
|
||||
.map(|r| {
|
||||
// update resource
|
||||
self.updated_resources.insert(TypeId::of::<R>());
|
||||
|
||||
r.as_any_mut().downcast_mut()
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
}
|
73
src/game.rs
73
src/game.rs
|
@ -1,9 +1,10 @@
|
|||
use std::{sync::Arc, cell::RefCell};
|
||||
use std::{sync::Arc, cell::RefCell, borrow::Borrow, collections::VecDeque};
|
||||
|
||||
use async_std::{task::block_on, sync::Mutex};
|
||||
|
||||
use hecs::World;
|
||||
//use hecs::World;
|
||||
use instant::Instant;
|
||||
use resources::{Resources, Resource};
|
||||
use tracing::{metadata::LevelFilter, info, debug, warn, error};
|
||||
use tracing_subscriber::{
|
||||
layer::{Layer, SubscriberExt},
|
||||
|
@ -13,7 +14,12 @@ use tracing_subscriber::{
|
|||
|
||||
use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode}, event_loop::{EventLoop, ControlFlow}};
|
||||
|
||||
use crate::{render::{renderer::{Renderer, BasicRenderer}, render_job::RenderJob}, input_event::InputEvent, ecs::{components::{mesh::MeshComponent, transform::TransformComponent}, SimpleSystem, SystemDispatcher}};
|
||||
use crate::{render::{renderer::{Renderer, BasicRenderer}, render_job::RenderJob}, input_event::InputEvent, ecs::{components::{mesh::MeshComponent, transform::TransformComponent}, SimpleSystem, SystemDispatcher, world::World}, input::Input};
|
||||
|
||||
pub struct Controls<'a> {
|
||||
pub world: &'a mut World,
|
||||
pub resources: &'a mut Resources,
|
||||
}
|
||||
|
||||
struct TickCounter {
|
||||
counter: u32,
|
||||
|
@ -75,6 +81,7 @@ 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,
|
||||
|
@ -82,12 +89,13 @@ struct GameLoop {
|
|||
}
|
||||
|
||||
impl GameLoop {
|
||||
pub async fn new(window: Arc<Window>, world: Arc<Mutex<World>>, user_systems: SystemDispatcher) -> GameLoop {
|
||||
pub async fn new(window: Arc<Window>, world: Arc<Mutex<World>>, resources: Arc<Mutex<Resources>>, 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(),
|
||||
|
@ -104,21 +112,20 @@ impl GameLoop {
|
|||
|
||||
async fn update(&mut self) {
|
||||
let mut world = self.world.lock().await;
|
||||
let mut resources = self.resources.lock().await;
|
||||
|
||||
if let Err(e) = self.engine_sys_dispatcher.execute_mut(&mut world) {
|
||||
let mut controls = Controls {
|
||||
world: &mut world,
|
||||
resources: &mut resources
|
||||
};
|
||||
|
||||
if let Err(e) = self.engine_sys_dispatcher.execute_mut(&mut controls) {
|
||||
error!("Error when executing engine ecs systems: '{}'", e);
|
||||
}
|
||||
|
||||
if let Err(e) = self.user_sys_dispatcher.execute_mut(&mut world) {
|
||||
if let Err(e) = self.user_sys_dispatcher.execute_mut(&mut controls) {
|
||||
error!("Error when executing user ecs systems: '{}'", e);
|
||||
}
|
||||
/* for esystem in self.engine_systems.iter_mut() {
|
||||
esystem.execute_mut(&mut world).unwrap();
|
||||
}
|
||||
|
||||
for system in self.systems.iter_mut() {
|
||||
system.execute_mut(&mut world).unwrap();
|
||||
} */
|
||||
}
|
||||
|
||||
async fn input_update(&mut self, event: &InputEvent) -> Option<ControlFlow> {
|
||||
|
@ -138,7 +145,7 @@ impl GameLoop {
|
|||
},
|
||||
|
||||
_ => {
|
||||
debug!("Got unhandled input event: \"{:?}\"", event);
|
||||
//debug!("Got unhandled input event: \"{:?}\"", event);
|
||||
|
||||
None
|
||||
}
|
||||
|
@ -164,9 +171,27 @@ impl GameLoop {
|
|||
ref event,
|
||||
window_id,
|
||||
} if window_id == self.window.id() => {
|
||||
|
||||
// If try_from failed, that means that the WindowEvent is not an
|
||||
// input related event.
|
||||
if let Ok(input_event) = InputEvent::try_from(event) {
|
||||
// Its possible to receive multiple input events before the update event for
|
||||
// the InputSystem is called, so we must use a queue for the events.
|
||||
{
|
||||
let mut world = self.world.lock().await;
|
||||
let event_queue = match world.query_res_mut::<VecDeque<InputEvent>>() {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
world.insert_resource(VecDeque::<InputEvent>::new());
|
||||
|
||||
// must succeed since it was just added
|
||||
world.query_res_mut::<VecDeque<InputEvent>>().unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
event_queue.push_back(input_event.clone());
|
||||
}
|
||||
|
||||
if let Some(new_control) = self.input_update(&input_event).await {
|
||||
*control_flow = new_control;
|
||||
}
|
||||
|
@ -202,6 +227,7 @@ impl GameLoop {
|
|||
|
||||
let mut world = self.world.lock().await;
|
||||
self.renderer.as_mut().prepare(&mut world).await;
|
||||
world.clear_updated_resources();
|
||||
drop(world);
|
||||
|
||||
match self.renderer.as_mut().render().await {
|
||||
|
@ -225,6 +251,7 @@ impl GameLoop {
|
|||
|
||||
pub struct Game {
|
||||
world: Option<Arc<Mutex<World>>>,
|
||||
resources: Option<Arc<Mutex<Resources>>>,
|
||||
system_dispatcher: Option<SystemDispatcher>
|
||||
}
|
||||
|
||||
|
@ -232,6 +259,7 @@ impl Default for Game {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
world: None,
|
||||
resources: Some(Arc::new(Mutex::new(Resources::new()))),
|
||||
system_dispatcher: Some(SystemDispatcher::new()),
|
||||
}
|
||||
}
|
||||
|
@ -282,15 +310,30 @@ 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, systems).await;
|
||||
let mut g_loop = GameLoop::new(Arc::clone(&window), world, resources, systems).await;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
g_loop.run_sync(event, control_flow);
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
use std::{any::Any, collections::{HashMap, hash_map::DefaultHasher, VecDeque}, hash::{Hash, Hasher}, sync::{Arc, Mutex}};
|
||||
|
||||
use gilrs_core::Gilrs;
|
||||
use tracing::warn;
|
||||
use winit::event::{VirtualKeyCode, ElementState};
|
||||
|
||||
use crate::{ecs::{SimpleSystem, world::Resource}, input_event::InputEvent};
|
||||
|
||||
pub type KeyCode = winit::event::VirtualKeyCode;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum ButtonEvent<T: Hash + '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::<VecDeque<InputEvent>>() {
|
||||
let event = queue.pop_front();
|
||||
|
||||
if let Some(input) = world.query_res_mut::<Input>() {
|
||||
input.update(event.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
events: HashMap<u64, Box<dyn Any + Send + Sync>>,
|
||||
}
|
||||
|
||||
impl Resource for Input {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Input {
|
||||
pub(crate) fn new() -> Self {
|
||||
let gilrs = match Gilrs::new() {
|
||||
Ok(g) => Some(Arc::new(Mutex::new(g))),
|
||||
Err(e) => {
|
||||
warn!("Failure to initialize gilrs, gamepads will not work!\n{}", e);
|
||||
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
Self {
|
||||
gilrs,
|
||||
events: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, event: Option<&InputEvent>) -> bool {
|
||||
// Convert JustPressed inputs to Pressed, and remove Released events
|
||||
self.events.retain(|_, v| {
|
||||
if let Some(ev) = v.downcast_mut::<ButtonEvent<KeyCode>>() {
|
||||
match ev {
|
||||
ButtonEvent::Released(_) => {
|
||||
return false;
|
||||
},
|
||||
ButtonEvent::JustPressed(v) => {
|
||||
*ev = ButtonEvent::Pressed(*v);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
|
||||
if let Some(event) = event {
|
||||
match event {
|
||||
InputEvent::KeyboardInput { input, .. } => {
|
||||
if let Some(code) = input.virtual_keycode {
|
||||
// Get a hash of the input code
|
||||
let mut hasher = DefaultHasher::new();
|
||||
code.hash(&mut hasher);
|
||||
let code_hash = hasher.finish();
|
||||
|
||||
// convert state
|
||||
let buttonev = Box::new(match input.state {
|
||||
ElementState::Pressed => ButtonEvent::JustPressed(code),
|
||||
ElementState::Released => ButtonEvent::Released(code),
|
||||
});
|
||||
|
||||
self.events.insert(code_hash, buttonev);
|
||||
}
|
||||
},
|
||||
/* WindowEvent::CursorMoved { position, .. } => Some(EventType::PositionChanged(position.x, position.y, InputEventCode::CursorMoved)),
|
||||
WindowEvent::CursorEntered { .. } => Some(EventType::Signal(InputEventCode::CursorEnteredWindow)),
|
||||
WindowEvent::CursorLeft { .. } => Some(EventType::Signal(InputEventCode::CursorLeftWindow)), */
|
||||
//WindowEvent::MouseWheel { delta, .. } => Some(EventType::AxisChanged(delta, InputEventCode::MouseWheel)),
|
||||
/* WindowEvent::MouseWheel { .. } => Some(InputEventCode::MouseWheel),
|
||||
WindowEvent::MouseInput { .. } => Some(InputEventCode::MouseInput),
|
||||
WindowEvent::TouchpadMagnify { .. } => Some(InputEventCode::TouchpadMagnify),
|
||||
WindowEvent::SmartMagnify { .. } => Some(InputEventCode::SmartMagnify),
|
||||
WindowEvent::TouchpadRotate { .. } => Some(InputEventCode::TouchpadRotate),
|
||||
WindowEvent::TouchpadPressure { .. } => Some(InputEventCode::TouchpadPressure),
|
||||
WindowEvent::AxisMotion { .. } => Some(InputEventCode::AxisMotion),
|
||||
WindowEvent::Touch { .. } => Some(InputEventCode::Touch), */
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// TODO: was_just_pressed
|
||||
|
||||
pub fn is_pressed(&self, code: VirtualKeyCode) -> bool {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
code.hash(&mut hasher);
|
||||
let inner_hash = hasher.finish();
|
||||
|
||||
if let Some(e) = self.events.get(&inner_hash) {
|
||||
if let Some(ev) = e.downcast_ref::<ButtonEvent<KeyCode>>() {
|
||||
match ev {
|
||||
ButtonEvent::Pressed(v) => {
|
||||
if v.clone() == code {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
ButtonEvent::JustPressed(v) => {
|
||||
if v.clone() == code {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
ButtonEvent::Released(_) => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
|
@ -1,6 +1,22 @@
|
|||
use winit::{event::{DeviceId, KeyboardInput, ModifiersState, MouseScrollDelta, TouchPhase, MouseButton, AxisId, Touch, WindowEvent, ElementState}, dpi::PhysicalPosition};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
use crate::ecs::world::Resource;
|
||||
|
||||
/// Wrapper around events from `winit::WindowEvent` that are specific to input related events.
|
||||
///
|
||||
/// The `winit::WindowEvent` enum has many values that are related to inputs.
|
||||
/// Ex:
|
||||
/// * winit::WindowEvent::KeyboardInput
|
||||
/// * winit::WindowEvent::CursorMoved
|
||||
/// * winit::WindowEvent::CursorEntered
|
||||
/// * winit::WindowEvent::MouseWheel
|
||||
/// * winit::WindowEvent::CursorLeft
|
||||
/// * winit::WindowEvent::MouseInput
|
||||
/// etc.
|
||||
///
|
||||
/// Its easier for these to all be in a single `InputEvent` type enum to check if any input was received.
|
||||
/// The comments for all the methods were taken from `winit::WindowEvent`
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum InputEvent {
|
||||
/// An event from the keyboard has been received.
|
||||
KeyboardInput {
|
||||
|
@ -216,33 +232,12 @@ impl<'a> TryFrom<&'a WindowEvent<'a>> for InputEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/* impl<'a> TryFrom<WindowEvent<'a>> for InputEvent {
|
||||
type Error = InputEventConversionError<'a>;
|
||||
|
||||
fn try_from(value: WindowEvent<'a>) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
WindowEvent::KeyboardInput { device_id, input, is_synthetic } =>
|
||||
Ok(InputEvent::KeyboardInput { device_id, input, is_synthetic }),
|
||||
WindowEvent::CursorMoved { device_id, position, modifiers } =>
|
||||
Ok(InputEvent::CursorMoved { device_id, position, modifiers }),
|
||||
WindowEvent::CursorEntered { device_id } => Ok(InputEvent::CursorEntered { device_id }),
|
||||
WindowEvent::CursorLeft { device_id } => Ok(InputEvent::CursorLeft { device_id }),
|
||||
WindowEvent::MouseWheel { device_id, delta, phase, modifiers } =>
|
||||
Ok(InputEvent::MouseWheel { device_id, delta, phase, modifiers }),
|
||||
WindowEvent::MouseInput { device_id, state, button, modifiers } =>
|
||||
Ok(InputEvent::MouseInput { device_id, state, button, modifiers }),
|
||||
WindowEvent::TouchpadMagnify { device_id, delta, phase } =>
|
||||
Ok(InputEvent::TouchpadMagnify { device_id, delta, phase }),
|
||||
WindowEvent::SmartMagnify { device_id } => Ok(InputEvent::SmartMagnify { device_id }),
|
||||
WindowEvent::TouchpadRotate { device_id, delta, phase } =>
|
||||
Ok(InputEvent::TouchpadRotate { device_id, delta, phase }),
|
||||
WindowEvent::TouchpadPressure { device_id, pressure, stage } =>
|
||||
Ok(InputEvent::TouchpadPressure { device_id, pressure, stage }),
|
||||
WindowEvent::AxisMotion { device_id, axis, value } =>
|
||||
Ok(InputEvent::AxisMotion { device_id, axis, value }),
|
||||
WindowEvent::Touch(t) => Ok(InputEvent::Touch(t)),
|
||||
|
||||
_ => Err(InputEventConversionError::FromError(value))
|
||||
}
|
||||
impl Resource for InputEvent {
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
} */
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
38
src/main.rs
38
src/main.rs
|
@ -4,14 +4,15 @@ mod input_event;
|
|||
mod resources;
|
||||
mod ecs;
|
||||
mod math;
|
||||
mod input;
|
||||
|
||||
use ecs::components::mesh::MeshComponent;
|
||||
|
||||
use ecs::components::transform::TransformComponent;
|
||||
use game::Game;
|
||||
use hecs::World;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::ecs::world::World;
|
||||
use crate::input::{Input, KeyCode, InputSystem};
|
||||
use crate::render::material::Material;
|
||||
use crate::render::texture::Texture;
|
||||
use crate::ecs::components::camera::CameraComponent;
|
||||
|
@ -84,16 +85,44 @@ 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 speed = 0.001;
|
||||
|
||||
let mut dir_x = 0.0;
|
||||
let mut dir_y = 0.0;
|
||||
|
||||
if input.is_pressed(KeyCode::A) {
|
||||
dir_x -= speed;
|
||||
}
|
||||
|
||||
if input.is_pressed(KeyCode::D) {
|
||||
dir_x += speed;
|
||||
}
|
||||
|
||||
if input.is_pressed(KeyCode::S) {
|
||||
dir_y -= speed;
|
||||
}
|
||||
|
||||
if input.is_pressed(KeyCode::W) {
|
||||
dir_y += speed;
|
||||
}
|
||||
|
||||
//debug!("dir: ({}, {})", dir_x, dir_y);
|
||||
|
||||
for (_eid, (transform, )) in world.query_mut::<(&mut TransformComponent,)>() {
|
||||
let t = &mut transform.transform;
|
||||
|
||||
debug!("Translation: {}", t.translation);
|
||||
/* debug!("Translation: {}", t.translation);
|
||||
|
||||
t.translation += glam::Vec3::new(0.0, 0.001, 0.0);
|
||||
t.translation.x *= -1.0
|
||||
t.translation.x *= -1.0 */
|
||||
t.translation.x += dir_x;
|
||||
t.translation.y += dir_y;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -102,5 +131,6 @@ async fn main() {
|
|||
Game::initialize().await
|
||||
.with_world(world)
|
||||
.with_system("jiggle", jiggle_system, &[])
|
||||
.with_system("input_system", InputSystem::new(), &[])
|
||||
.run().await;
|
||||
}
|
||||
|
|
|
@ -11,11 +11,12 @@ use wgpu::{BindGroup, BindGroupLayout};
|
|||
use wgpu::util::DeviceExt;
|
||||
use winit::window::Window;
|
||||
|
||||
use hecs::{World, Entity};
|
||||
use hecs::Entity;
|
||||
|
||||
use crate::ecs::components::camera::CameraComponent;
|
||||
use crate::ecs::components::mesh::MeshComponent;
|
||||
use crate::ecs::components::transform::TransformComponent;
|
||||
use crate::ecs::world::World;
|
||||
use crate::math::{Transform, Angle};
|
||||
use crate::resources;
|
||||
|
||||
|
|
Loading…
Reference in New Issue