Huge input update, FPS Camera controls system
Long day. I now store winit:🪟:Window in a mutex.
This commit is contained in:
parent
1e9b997aeb
commit
46c8c32819
15 changed files with 307 additions and 39 deletions
|
|
@ -10,3 +10,4 @@ raidillon_platform = { path = "../platform" }
|
|||
winit = "0.30.12"
|
||||
hecs = "0.10.5"
|
||||
indexmap = "2.10.0"
|
||||
glam = "0.30.8"
|
||||
|
|
@ -5,11 +5,13 @@ use crate::system::{SystemContext, SystemManager};
|
|||
use raidillon_platform::PlatformContext;
|
||||
use raidillon_core::DebugUIBuffer;
|
||||
use raidillon_core::engine::EngineTrait;
|
||||
use crate::input::InputState;
|
||||
|
||||
pub struct Engine {
|
||||
pub scene_manager: SceneManager,
|
||||
pub system_manager: SystemManager,
|
||||
debug_ui_buffer: Rc<RefCell<DebugUIBuffer>>,
|
||||
input_state: Rc<RefCell<InputState>>,
|
||||
}
|
||||
|
||||
impl EngineTrait for Engine {
|
||||
|
|
@ -21,6 +23,7 @@ impl EngineTrait for Engine {
|
|||
scene_manager,
|
||||
system_manager,
|
||||
debug_ui_buffer: Rc::new(RefCell::new(DebugUIBuffer::new())),
|
||||
input_state: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -35,6 +38,7 @@ impl EngineTrait for Engine {
|
|||
scene: self.scene_manager.current_mut(),
|
||||
platform_context,
|
||||
debug_ui_buffer: self.debug_ui_buffer.clone(),
|
||||
input_state: self.input_state.clone(),
|
||||
};
|
||||
|
||||
// Engine Loading Stage 2: load world
|
||||
|
|
@ -50,6 +54,7 @@ impl EngineTrait for Engine {
|
|||
scene: self.scene_manager.current_mut(),
|
||||
platform_context,
|
||||
debug_ui_buffer: self.debug_ui_buffer.clone(),
|
||||
input_state: self.input_state.clone(),
|
||||
};
|
||||
|
||||
for system in self.system_manager.systems.values_mut() {
|
||||
|
|
@ -62,6 +67,7 @@ impl EngineTrait for Engine {
|
|||
scene: self.scene_manager.current_mut(),
|
||||
platform_context,
|
||||
debug_ui_buffer: self.debug_ui_buffer.clone(),
|
||||
input_state: self.input_state.clone(),
|
||||
};
|
||||
|
||||
for system in self.system_manager.systems.values_mut() {
|
||||
|
|
@ -70,10 +76,13 @@ impl EngineTrait for Engine {
|
|||
}
|
||||
|
||||
fn handle_event(&mut self, platform_context: PlatformContext) {
|
||||
self.input_state.borrow_mut().handle_event(&platform_context.current_event);
|
||||
|
||||
let mut ctx = SystemContext {
|
||||
scene: self.scene_manager.current_mut(),
|
||||
platform_context,
|
||||
debug_ui_buffer: self.debug_ui_buffer.clone(),
|
||||
input_state: self.input_state.clone(),
|
||||
};
|
||||
|
||||
for system in self.system_manager.systems.values_mut() {
|
||||
|
|
|
|||
69
engine/src/input.rs
Normal file
69
engine/src/input.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
use std::collections::HashSet;
|
||||
use winit::event::{ElementState, Event, MouseButton, WindowEvent};
|
||||
use winit::keyboard::{KeyCode, PhysicalKey};
|
||||
|
||||
/// A utility to help with buffering input.
|
||||
/// Meant to be plugged into systems.
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct InputState {
|
||||
held_keys: HashSet<KeyCode>,
|
||||
held_mouse: HashSet<MouseButton>,
|
||||
}
|
||||
|
||||
impl InputState {
|
||||
fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn handle_event(&mut self, event: &Event<()>) {
|
||||
if let Event::WindowEvent { event, .. } = event {
|
||||
match event {
|
||||
// Keyboard
|
||||
WindowEvent::KeyboardInput { event: key_event, .. } => {
|
||||
if let PhysicalKey::Code(code) = key_event.physical_key {
|
||||
match key_event.state {
|
||||
ElementState::Pressed => {
|
||||
self.held_keys.insert(code);
|
||||
}
|
||||
ElementState::Released => {
|
||||
self.held_keys.remove(&code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse
|
||||
WindowEvent::MouseInput { state, button, .. } => {
|
||||
match state {
|
||||
ElementState::Pressed => {
|
||||
self.held_mouse.insert(*button);
|
||||
}
|
||||
ElementState::Released => {
|
||||
self.held_mouse.remove(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WindowEvent::Focused(focused) => {
|
||||
if !*focused {
|
||||
self.clear();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn key_held(&self, code: KeyCode) -> bool {
|
||||
self.held_keys.contains(&code)
|
||||
}
|
||||
|
||||
pub fn mouse_held(&self, button: MouseButton) -> bool {
|
||||
self.held_mouse.contains(&button)
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.held_keys.clear();
|
||||
self.held_mouse.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
pub mod engine;
|
||||
pub mod system;
|
||||
mod input;
|
||||
pub mod systems;
|
||||
|
||||
pub use crate::engine::Engine;
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@ use raidillon_platform::PlatformContext;
|
|||
use std::any::TypeId;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use crate::input::InputState;
|
||||
|
||||
pub struct SystemContext<'a> {
|
||||
// TODO: time delta etc.
|
||||
pub scene: &'a mut Scene,
|
||||
pub platform_context: PlatformContext,
|
||||
pub debug_ui_buffer: Rc<RefCell<DebugUIBuffer>>,
|
||||
pub input_state: Rc<RefCell<InputState>>,
|
||||
}
|
||||
|
||||
pub trait System {
|
||||
|
|
|
|||
114
engine/src/systems/fps_camera.rs
Normal file
114
engine/src/systems/fps_camera.rs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
use crate::system::{System, SystemContext};
|
||||
use glam::{Quat, Vec3};
|
||||
use winit::event::DeviceEvent::MouseMotion;
|
||||
use winit::event::{ElementState, Event, MouseButton, WindowEvent};
|
||||
use winit::keyboard::PhysicalKey;
|
||||
use winit::window::CursorGrabMode;
|
||||
use raidillon_assets::model_path;
|
||||
use raidillon_platform::Camera;
|
||||
|
||||
pub struct FPSCameraSystem {
|
||||
mouse_delta: (f64, f64),
|
||||
mouse_enabled: bool,
|
||||
position: Vec3,
|
||||
yaw: f32,
|
||||
pitch: f32,
|
||||
speed: f32,
|
||||
sensitivity: f32,
|
||||
}
|
||||
|
||||
impl Default for FPSCameraSystem {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mouse_delta: Default::default(),
|
||||
mouse_enabled: Default::default(),
|
||||
position: Vec3::new(0.0, 0.0, 2.0),
|
||||
yaw: -90.0,
|
||||
pitch: 0.0,
|
||||
speed: 3.0,
|
||||
sensitivity: 0.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl System for FPSCameraSystem {
|
||||
fn load_world(&mut self, ctx: &mut SystemContext) {
|
||||
ctx.scene.world.spawn((Camera {
|
||||
eye: Vec3::new(0.0, 0.0, 2.0),
|
||||
center: Vec3::ZERO,
|
||||
up: Vec3::Y,
|
||||
fovy: 60_f32.to_radians(),
|
||||
aspect: ctx.platform_context.frame_width / ctx.platform_context.frame_height,
|
||||
znear: 0.1,
|
||||
zfar: 100.0,
|
||||
},));
|
||||
}
|
||||
|
||||
fn handle_event(&mut self, ctx: &mut SystemContext) {
|
||||
let event2 = ctx.platform_context.current_event.clone();
|
||||
match event2 {
|
||||
Event::DeviceEvent { device_id, event} => {
|
||||
match event {
|
||||
MouseMotion { delta } => {
|
||||
self.mouse_delta.0 += delta.0;
|
||||
self.mouse_delta.1 += delta.1;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::MouseInput { state, button, .. } => {
|
||||
if button == MouseButton::Right {
|
||||
// blood and tear
|
||||
let window = ctx.platform_context.window.lock().unwrap();
|
||||
match state {
|
||||
ElementState::Pressed => {
|
||||
if window
|
||||
.set_cursor_grab(CursorGrabMode::Confined)
|
||||
.or_else(|_| window.set_cursor_grab(CursorGrabMode::Locked))
|
||||
.is_ok()
|
||||
{
|
||||
window.set_cursor_visible(false);
|
||||
self.mouse_enabled = true;
|
||||
}
|
||||
}
|
||||
ElementState::Released => {
|
||||
let _ = window.set_cursor_grab(CursorGrabMode::None);
|
||||
window.set_cursor_visible(true);
|
||||
self.mouse_enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn frame_update(&mut self, ctx: &mut SystemContext) {
|
||||
if self.mouse_enabled {
|
||||
self.yaw += self.mouse_delta.0 as f32 * self.sensitivity;
|
||||
self.pitch -= self.mouse_delta.1 as f32 * self.sensitivity;
|
||||
self.pitch = self.pitch.clamp(-89.0, 89.0);
|
||||
}
|
||||
|
||||
ctx.scene.world.query_mut::<&mut Camera>().into_iter().for_each(|(_, camera)| {
|
||||
camera.eye = self.position;
|
||||
camera.center = self.position + self.front();
|
||||
});
|
||||
self.mouse_delta = (0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl FPSCameraSystem {
|
||||
pub fn front(&self) -> Vec3 {
|
||||
let yaw_rad = self.yaw.to_radians();
|
||||
let pitch_rad = self.pitch.to_radians();
|
||||
Vec3::new(
|
||||
yaw_rad.cos() * pitch_rad.cos(),
|
||||
pitch_rad.sin(),
|
||||
yaw_rad.sin() * pitch_rad.cos(),
|
||||
).normalize()
|
||||
}
|
||||
}
|
||||
1
engine/src/systems/mod.rs
Normal file
1
engine/src/systems/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub mod fps_camera;
|
||||
Loading…
Add table
Add a link
Reference in a new issue