Compare commits

..

2 Commits

Author SHA1 Message Date
SeanOMik 75c0377d9c
Create structs for the input actions
ci/woodpecker/push/build Pipeline was successful Details
2023-11-04 11:34:27 -04:00
SeanOMik 76f81d6b02
Create an input module to cleanup code 2023-11-03 21:07:02 -04:00
11 changed files with 622 additions and 355 deletions

View File

@ -1,4 +1,4 @@
use lyra_engine::{math::{self, Vec3}, ecs::{World, components::{transform::TransformComponent, camera::CameraComponent, model::ModelComponent, DeltaTime}, EventQueue, SimpleSystem, Component, Criteria, CriteriaSchedule, BatchedSystem}, math::Transform, input::{KeyCode, InputButtons, MouseMotion}, game::Game, plugin::Plugin, render::window::{CursorGrabMode, WindowOptions}, change_tracker::Ct};
use lyra_engine::{math::{self, Vec3}, ecs::{World, components::{transform::TransformComponent, camera::CameraComponent, model::ModelComponent, DeltaTime}, EventQueue, SimpleSystem, Component, Criteria, CriteriaSchedule, BatchedSystem}, math::Transform, input::{KeyCode, InputButtons, MouseMotion, ActionHandler, Layout, Action, ActionKind, LayoutId, ActionMapping, Binding, ActionSource, ActionMappingId}, game::Game, plugin::Plugin, render::window::{CursorGrabMode, WindowOptions}, change_tracker::Ct};
use lyra_engine::assets::{ResourceManager, Model};
mod free_fly_camera;
@ -58,6 +58,22 @@ struct TpsAccumulator(f32);
#[async_std::main]
async fn main() {
let _action_handler = ActionHandler::new()
.add_layout(LayoutId::from(0))
.add_action("forward_backward", Action::new(ActionKind::Button))
.add_action("left_right", Action::new(ActionKind::Button))
.add_mapping(ActionMapping::new(LayoutId::from(0), ActionMappingId::from(0))
.bind("forward_backward", &[
ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0),
ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0)
])
.bind("left_right", &[
ActionSource::Keyboard(KeyCode::A).into_binding_modifier(1.0),
ActionSource::Keyboard(KeyCode::D).into_binding_modifier(-1.0)
])
.finish()
);
let setup_sys = |world: &mut World| -> anyhow::Result<()> {
{
let mut window_options = world.get_resource_mut::<Ct<WindowOptions>>().unwrap();

View File

@ -12,7 +12,7 @@ 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}, window::WindowOptions}, input_event::InputEvent, ecs::{SimpleSystem, SystemDispatcher, EventQueue, Events}, plugin::Plugin, change_tracker::Ct};
use crate::{render::{renderer::{Renderer, BasicRenderer}, window::WindowOptions}, input::InputEvent, ecs::{SimpleSystem, SystemDispatcher, EventQueue, Events}, plugin::Plugin, change_tracker::Ct};
pub struct Controls<'a> {
pub world: &'a mut edict::World,

View File

@ -1,351 +0,0 @@
use std::{collections::{HashMap, hash_map::DefaultHasher}, hash::{Hash, Hasher}};
use glam::Vec2;
use tracing::debug;
use winit::event::{ElementState, MouseScrollDelta};
use crate::{ecs::{SimpleSystem, EventQueue}, input_event::InputEvent, plugin::Plugin,};
pub type KeyCode = winit::event::VirtualKeyCode;
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub enum ButtonEvent<T: Clone + Hash + Eq + PartialEq + 'static> {
Pressed(T),
Released(T),
JustPressed(T),
}
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,
}
}
fn clone_val(&self) -> T {
self.clone().take_val()
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct MouseMotion {
pub delta: Vec2,
}
#[derive(Clone, Debug, PartialEq)]
pub struct MouseWheel {
pub delta: Vec2,
}
#[derive(Clone, Debug, PartialEq)]
pub struct MouseExact {
pub pos: Vec2,
}
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum TouchPhase {
Started,
Moved,
Ended,
Cancelled,
}
impl From<winit::event::TouchPhase> for TouchPhase {
fn from(value: winit::event::TouchPhase) -> Self {
match value {
winit::event::TouchPhase::Started => TouchPhase::Started,
winit::event::TouchPhase::Moved => TouchPhase::Moved,
winit::event::TouchPhase::Ended => TouchPhase::Ended,
winit::event::TouchPhase::Cancelled => TouchPhase::Cancelled,
}
}
}
/// Translated `Force` from `winit` crate
#[derive(Clone, Debug, PartialEq)]
pub enum Force {
Calibrated {
force: f64,
max_possible_force: f64,
altitude_angle: Option<f64>,
},
Normalized(f64),
}
impl From<winit::event::Force> for Force {
fn from(value: winit::event::Force) -> Self {
match value {
winit::event::Force::Calibrated { force, max_possible_force, altitude_angle } => Self::Calibrated { force, max_possible_force, altitude_angle },
winit::event::Force::Normalized(v) => Self::Normalized(v),
}
}
}
/// Translated `WindowEvent::Touch` from `winit` crate
#[derive(Clone, Debug, PartialEq)]
pub struct Touch {
pub phase: TouchPhase,
pub location: Vec2,
pub force: Option<Force>,
pub finger_id: u64,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Touches {
pub touches: Vec<Touch>,
}
impl Default for Touches {
fn default() -> Self {
Self::new()
}
}
impl Touches {
pub fn new() -> Self {
Self {
touches: Vec::new()
}
}
}
/// A mouse button event
///
/// Translated `WindowEvent::MouseButton` from `winit` crate
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum MouseButton {
Left,
Right,
Middle,
Other(u16),
}
#[derive(Clone, Debug, PartialEq)]
pub enum MouseScrollUnit {
Line(Vec2),
Pixel(Vec2)
}
#[derive(Clone, Debug, PartialEq)]
pub struct MouseScroll {
pub unit: MouseScrollUnit,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CursorEnteredWindow;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CursorLeftWindow;
#[derive(Clone)]
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<T: Clone + Hash + Eq + PartialEq + 'static> Default for InputButtons<T> {
fn default() -> Self {
Self::new()
}
}
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) {
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
});
}
}
#[derive(Default)]
pub struct InputSystem;
impl InputSystem {
pub fn update(&mut self, event: &InputEvent, world: &mut edict::World) -> bool {
let event_queue = world.get_resource_mut::<EventQueue>();
if event_queue.is_none() {
return false;
}
let mut event_queue = event_queue.unwrap();
match event {
InputEvent::KeyboardInput { input, .. } => {
if let Some(code) = input.virtual_keycode {
drop(event_queue);
let e = world.with_resource(InputButtons::<KeyCode>::new);
//let mut e = with_resource_mut(world, || InputButtons::<KeyCode>::new());
e.add_input_from_winit(code, input.state);
}
},
InputEvent::MouseMotion { delta, .. } => {
let delta = MouseMotion {
delta: Vec2::new(delta.0 as f32, delta.1 as f32)
};
event_queue.trigger_event(delta);
},
InputEvent::CursorMoved { position, .. } => {
let exact = MouseExact {
pos: Vec2::new(position.x as f32, position.y as f32)
};
event_queue.trigger_event(exact);
},
InputEvent::CursorEntered { .. } => {
let event = CursorEnteredWindow {};
event_queue.trigger_event(event);
},
InputEvent::CursorLeft { .. } => {
let event = CursorLeftWindow {};
event_queue.trigger_event(event);
},
InputEvent::MouseWheel { delta, .. } => {
let event = match delta {
MouseScrollDelta::LineDelta(x, y) => MouseScroll {
unit: MouseScrollUnit::Line(Vec2::new(*x, *y)),
},
MouseScrollDelta::PixelDelta(delta) => MouseScroll {
unit: MouseScrollUnit::Pixel(Vec2::new(delta.x as f32, delta.y as f32)),
},
};
event_queue.trigger_event(event);
}, //MouseButton
InputEvent::MouseInput { button, state, .. } => {
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),
};
event_queue.trigger_event(button_event);
drop(event_queue);
let e = world.with_resource(InputButtons::<MouseButton>::new);
e.add_input_from_winit(button_event, *state);
},
InputEvent::Touch(t) => {
drop(event_queue);
let touch = Touch {
phase: TouchPhase::from(t.phase),
location: Vec2::new(t.location.x as f32, t.location.y as f32),
force: t.force.map(Force::from),
finger_id: t.id,
};
let touches = world.with_resource(Touches::new);
touches.touches.push(touch);
},
_ => {},
}
false
}
}
impl SimpleSystem for InputSystem {
fn execute_mut(&mut self, world: &mut edict::World) -> anyhow::Result<()> {
let queue = world.get_resource_mut::<EventQueue>()
.and_then(|q| q.read_events::<InputEvent>());
if queue.is_none() {
return Ok(());
}
let mut events = queue.unwrap();
while let Some(event) = events.pop_front() {
self.update(&event, world);
}
Ok(())
}
}
/// Plugin that runs InputSystem
#[derive(Default)]
pub struct InputPlugin;
impl Plugin for InputPlugin {
fn setup(&self, game: &mut crate::game::Game) {
game.with_system("input", InputSystem, &[]);
}
}

253
src/input/action.rs Normal file
View File

@ -0,0 +1,253 @@
use std::{collections::HashMap, cell::RefCell, borrow::BorrowMut};
use edict::action;
use crate::castable_any::CastableAny;
use super::{Button, KeyCode};
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
enum GamepadFormat {
DualAxis,
Joystick,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
enum GamepadButton {
FaceBottom,
FaceLeft,
FaceRight,
FaceTop,
VirtualConfirm,
VirtualDeny,
LThumbstick,
RThumbstick,
DPadUp,
DPadDown,
DPadLeft,
DPadRight,
LShoulder,
RShoulder,
LTrigger,
RTrigger,
Special,
LSpecial,
RSpecial,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
enum GamepadAxis {
LThumbstickX,
LThumbstickY,
RThumbstickX,
RThumbstickY,
LTrigger,
RTrigger,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
enum GamepadInput {
Button(GamepadButton),
Axis(GamepadAxis),
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ActionSource {
Keyboard(KeyCode),
Gamepad(GamepadFormat, GamepadInput),
}
impl ActionSource {
/// Convert this Source into a Binding. Uses a default Binding modifier value of `1.0`.
pub fn into_binding(self) -> Binding {
Binding::from_source(self)
}
/// Convert this Source into a Binding, setting the modifier.
pub fn into_binding_modifier(self, modifier: f32) -> Binding {
Binding::from_source_modifier(self, modifier)
}
}
#[derive(Clone, Debug)]
pub struct Binding {
pub source: ActionSource,
pub modifier: f32,
}
impl Binding {
/// Create a binding from a Source. Uses a default value of `1.0` as the modifier.
pub fn from_source(source: ActionSource) -> Self {
Self {
source,
modifier: 1.0,
}
}
/// Create a binding from a Source, with a modifier
pub fn from_source_modifier(source: ActionSource, modifier: f32) -> Self {
Self {
source,
modifier,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ActionKind {
Button,
Axis
}
#[derive(Clone, Debug)]
pub struct Action {
kind: ActionKind,
}
impl Action {
pub fn new(kind: ActionKind) -> Self {
Self {
kind,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct LayoutId(u32);
impl From<u32> for LayoutId {
fn from(value: u32) -> Self {
Self(value)
}
}
impl Default for LayoutId {
fn default() -> Self {
Self(0)
}
}
#[derive(Clone)]
pub struct Layout {
mappings: HashMap<ActionMappingId, ActionMapping>,
}
impl Layout {
pub fn new() -> Self {
Self {
mappings: HashMap::new(),
}
}
pub fn add_mapping(&mut self, mapping: ActionMapping) -> &mut Self {
self.mappings.insert(mapping.id, mapping);
self
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ActionMappingId(u32);
impl From<u32> for ActionMappingId {
fn from(value: u32) -> Self {
Self(value)
}
}
impl Default for ActionMappingId {
fn default() -> Self {
Self(0)
}
}
#[derive(Clone)]
pub struct ActionMapping {
layout: LayoutId,
id: ActionMappingId,
action_binds: HashMap<String, Vec<Binding>>,
}
impl ActionMapping {
pub fn new(layout: LayoutId, id: ActionMappingId) -> Self {
Self {
layout,
id,
action_binds: HashMap::new(),
}
}
/// Creates a binding for the action.
///
/// If the action is not in this layout, this will panic!
///
/// Parameters:
/// * `action_label` - The label corresponding to the action in this Layout.
/// * `bind` - The Binding to add to the Action.
pub fn bind(mut self, action_label: &str, bindings: &[Binding]) -> Self {
let mut bindings = bindings.to_vec();
let action_binds = self.action_binds.entry(action_label.to_string())
.or_insert_with(|| Vec::new());
action_binds.append(&mut bindings);
self
}
/// Creates multiple binding for the action.
///
/// If the action is not in this layout, this will panic!
///
/// Parameters:
/// * `action_label` - The label corresponding to the action in this Layout.
/// * `bindings` - The list of Bindings to add to the Action.
/* pub fn add_bindings(&mut self, action_label: String, bindings: &[Binding]) -> &mut Self {
let mut bindings = bindings.to_vec();
let action_binds = self.action_binds.entry(action_label)
.or_insert_with(|| Vec::new());
action_binds.append(&mut bindings);
self
} */
pub fn finish(self) -> Self {
self
}
}
pub struct ActionHandler {
actions: HashMap<String, Action>,
layouts: HashMap<LayoutId, Layout>,
current_layout: LayoutId,
}
impl ActionHandler {
pub fn new() -> Self {
Self {
actions: HashMap::new(),
layouts: HashMap::new(),
current_layout: LayoutId::default(),
}
}
pub fn add_layout(&mut self, id: LayoutId) -> &mut Self {
self.layouts.insert(id, Layout::new());
self
}
pub fn add_action(&mut self, label: &str, action: Action) -> &mut Self {
/* let layout = self.layouts.get_mut(&layout_id).unwrap();
layout.actions.insert(label.to_string(), action); */
self.actions.insert(label.to_string(), action);
self
}
pub fn add_mapping(&mut self, mapping: ActionMapping) -> &mut Self {
let layout = self.layouts.get_mut(&mapping.layout).unwrap();
layout.add_mapping(mapping);
self
}
}

101
src/input/buttons.rs Normal file
View File

@ -0,0 +1,101 @@
use std::{hash::{Hash, Hasher}, collections::{HashMap, hash_map::DefaultHasher}};
use winit::event::ElementState;
//pub trait Button : Clone + Hash + Eq + PartialEq + 'static {}
/* pub trait Button {}
impl<T: Clone + Hash + Eq + PartialEq + 'static> Button for T {} */
pub trait Button = Clone + Hash + Eq + PartialEq + 'static;
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub enum ButtonEvent<T: Button> {
Pressed(T),
Released(T),
JustPressed(T),
}
impl<T: Button> ButtonEvent<T> {
fn take_val(self) -> T {
match self {
ButtonEvent::Pressed(t) => t,
ButtonEvent::JustPressed(t) => t,
ButtonEvent::Released(t) => t,
}
}
fn clone_val(&self) -> T {
self.clone().take_val()
}
}
#[derive(Clone)]
pub struct InputButtons<T: Button> {
// the u64 as the key is the hashed value of T. this makes it easier to
// search for a button and see its state
button_events: HashMap<u64, ButtonEvent<T>>,
}
impl<T: Button> Default for InputButtons<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Button> InputButtons<T> {
pub fn new() -> Self {
Self {
button_events: HashMap::new(),
}
}
fn get_button_hash(button: &T) -> u64 {
let mut hasher = DefaultHasher::new();
button.hash(&mut hasher);
hasher.finish()
}
/// Add a button event to this input type
pub fn add_input(&mut self, button: ButtonEvent<T>) {
let hash = Self::get_button_hash(&button.clone_val());
self.button_events.insert(hash, button);
}
pub(crate) fn add_input_from_winit(&mut self, button: T, state: ElementState) {
let event = match state {
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
}
}
}

109
src/input/events.rs Normal file
View File

@ -0,0 +1,109 @@
#[derive(Clone, Debug, PartialEq)]
pub struct MouseMotion {
pub delta: glam::Vec2,
}
#[derive(Clone, Debug, PartialEq)]
pub struct MouseWheel {
pub delta: glam::Vec2,
}
#[derive(Clone, Debug, PartialEq)]
pub struct MouseExact {
pub pos: glam::Vec2,
}
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum TouchPhase {
Started,
Moved,
Ended,
Cancelled,
}
impl From<winit::event::TouchPhase> for TouchPhase {
fn from(value: winit::event::TouchPhase) -> Self {
match value {
winit::event::TouchPhase::Started => TouchPhase::Started,
winit::event::TouchPhase::Moved => TouchPhase::Moved,
winit::event::TouchPhase::Ended => TouchPhase::Ended,
winit::event::TouchPhase::Cancelled => TouchPhase::Cancelled,
}
}
}
/// Translated `Force` from `winit` crate
#[derive(Clone, Debug, PartialEq)]
pub enum Force {
Calibrated {
force: f64,
max_possible_force: f64,
altitude_angle: Option<f64>,
},
Normalized(f64),
}
impl From<winit::event::Force> for Force {
fn from(value: winit::event::Force) -> Self {
match value {
winit::event::Force::Calibrated { force, max_possible_force, altitude_angle } => Self::Calibrated { force, max_possible_force, altitude_angle },
winit::event::Force::Normalized(v) => Self::Normalized(v),
}
}
}
/// Translated `WindowEvent::Touch` from `winit` crate
#[derive(Clone, Debug, PartialEq)]
pub struct Touch {
pub phase: TouchPhase,
pub location: glam::Vec2,
pub force: Option<Force>,
pub finger_id: u64,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Touches {
pub touches: Vec<Touch>,
}
impl Default for Touches {
fn default() -> Self {
Self::new()
}
}
impl Touches {
pub fn new() -> Self {
Self {
touches: Vec::new()
}
}
}
/// A mouse button event
///
/// Translated `WindowEvent::MouseButton` from `winit` crate
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum MouseButton {
Left,
Right,
Middle,
Other(u16),
}
#[derive(Clone, Debug, PartialEq)]
pub enum MouseScrollUnit {
Line(glam::Vec2),
Pixel(glam::Vec2)
}
#[derive(Clone, Debug, PartialEq)]
pub struct MouseScroll {
pub unit: MouseScrollUnit,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CursorEnteredWindow;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CursorLeftWindow;

14
src/input/mod.rs Normal file
View File

@ -0,0 +1,14 @@
pub mod system;
pub use system::*;
pub mod input_event;
pub use input_event::*;
pub mod events;
pub use events::*;
pub mod buttons;
pub use buttons::*;
pub mod action;
pub use action::*;

125
src/input/system.rs Executable file
View File

@ -0,0 +1,125 @@
use glam::Vec2;
use winit::event::MouseScrollDelta;
use crate::{ecs::{SimpleSystem, EventQueue}, plugin::Plugin,};
use super::{events::*, InputButtons, InputEvent};
pub type KeyCode = winit::event::VirtualKeyCode;
#[derive(Default)]
pub struct InputSystem;
impl InputSystem {
pub fn process_event(&mut self, world: &mut edict::World, event: &InputEvent) -> bool {
let event_queue = world.get_resource_mut::<EventQueue>();
if event_queue.is_none() {
return false;
}
let mut event_queue = event_queue.unwrap();
match event {
InputEvent::KeyboardInput { input, .. } => {
if let Some(code) = input.virtual_keycode {
drop(event_queue);
let e = world.with_resource(InputButtons::<winit::event::VirtualKeyCode>::new);
//let mut e = with_resource_mut(world, || InputButtons::<KeyCode>::new());
e.add_input_from_winit(code, input.state);
}
},
InputEvent::MouseMotion { delta, .. } => {
let delta = MouseMotion {
delta: Vec2::new(delta.0 as f32, delta.1 as f32)
};
event_queue.trigger_event(delta);
},
InputEvent::CursorMoved { position, .. } => {
let exact = MouseExact {
pos: Vec2::new(position.x as f32, position.y as f32)
};
event_queue.trigger_event(exact);
},
InputEvent::CursorEntered { .. } => {
let event = CursorEnteredWindow {};
event_queue.trigger_event(event);
},
InputEvent::CursorLeft { .. } => {
let event = CursorLeftWindow {};
event_queue.trigger_event(event);
},
InputEvent::MouseWheel { delta, .. } => {
let event = match delta {
MouseScrollDelta::LineDelta(x, y) => MouseScroll {
unit: MouseScrollUnit::Line(Vec2::new(*x, *y)),
},
MouseScrollDelta::PixelDelta(delta) => MouseScroll {
unit: MouseScrollUnit::Pixel(Vec2::new(delta.x as f32, delta.y as f32)),
},
};
event_queue.trigger_event(event);
}, //MouseButton
InputEvent::MouseInput { button, state, .. } => {
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),
};
event_queue.trigger_event(button_event);
drop(event_queue);
let e = world.with_resource(InputButtons::<MouseButton>::new);
e.add_input_from_winit(button_event, *state);
},
InputEvent::Touch(t) => {
drop(event_queue);
let touch = Touch {
phase: TouchPhase::from(t.phase),
location: Vec2::new(t.location.x as f32, t.location.y as f32),
force: t.force.map(Force::from),
finger_id: t.id,
};
let touches = world.with_resource(Touches::new);
touches.touches.push(touch);
},
_ => {},
}
false
}
}
impl SimpleSystem for InputSystem {
fn execute_mut(&mut self, world: &mut edict::World) -> anyhow::Result<()> {
let queue = world.get_resource_mut::<EventQueue>()
.and_then(|q| q.read_events::<InputEvent>());
if queue.is_none() {
return Ok(());
}
let mut events = queue.unwrap();
while let Some(event) = events.pop_front() {
self.process_event(world, &event);
}
Ok(())
}
}
/// Plugin that runs InputSystem
#[derive(Default)]
pub struct InputPlugin;
impl Plugin for InputPlugin {
fn setup(&self, game: &mut crate::game::Game) {
game.with_system("input", InputSystem, &[]);
}
}

View File

@ -1,9 +1,9 @@
#![feature(hash_extract_if)]
#![feature(lint_reasons)]
#![feature(trait_alias)]
pub mod game;
pub mod render;
pub mod input_event;
pub mod resources;
pub mod ecs;
pub mod math;

View File

@ -6,7 +6,7 @@ use winit::{window::{Window, Fullscreen}, dpi::{LogicalPosition, LogicalSize, Ph
pub use winit::window::{CursorGrabMode, CursorIcon, Icon, Theme, WindowButtons, WindowLevel};
use crate::{plugin::Plugin, change_tracker::Ct, ecs::EventQueue, input_event::InputEvent};
use crate::{plugin::Plugin, change_tracker::Ct, ecs::EventQueue, input::InputEvent};
#[derive(Default, Clone)]
pub enum WindowMode {