Add raidillon_input and FPSCameraController

This commit is contained in:
reo 2025-07-18 12:09:24 +03:00
parent d0440f3da3
commit 97195fbd05
7 changed files with 268 additions and 0 deletions

View file

@ -0,0 +1,73 @@
use glam::Vec3;
use std::hash::Hash;
use super::Input;
#[derive(Debug, Clone)]
pub struct FPSCameraController {
pub position: Vec3,
yaw: f32,
pitch: f32,
pub speed: f32,
pub sensitivity: f32,
}
impl FPSCameraController {
pub fn new(position: Vec3) -> Self {
Self {
position,
yaw: -90.0,
pitch: 0.0,
speed: 3.0,
sensitivity: 0.1,
}
}
pub fn update<A>(&mut self,
input: &Input<A>,
dt: f32,
mouse_enabled: bool,
actions: (A, A, A, A))
where
A: Copy + Eq + Hash,
{
let (forward, backward, left, right) = actions;
// Mouse look
if mouse_enabled {
let (dx, dy) = input.mouse_delta();
self.yaw += dx as f32 * self.sensitivity;
self.pitch -= dy as f32 * self.sensitivity;
self.pitch = self.pitch.clamp(-89.0, 89.0);
}
// Movement
let front = self.front();
let right_vec = front.cross(Vec3::Y).normalize();
let frame_speed = self.speed * dt;
if input.action_held(forward) {
self.position += front * frame_speed;
}
if input.action_held(backward) {
self.position -= front * frame_speed;
}
if input.action_held(left) {
self.position -= right_vec * frame_speed;
}
if input.action_held(right) {
self.position += right_vec * frame_speed;
}
}
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()
}
}

107
raidillon_input/src/lib.rs Normal file
View file

@ -0,0 +1,107 @@
use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use winit::event::{DeviceEvent, ElementState, Event, WindowEvent};
use winit::keyboard::{KeyCode, PhysicalKey};
pub mod camera;
pub use camera::FPSCameraController;
pub struct Input<A: Copy + Eq + Hash> {
pressed_keys: HashSet<KeyCode>,
pressed_once: HashSet<KeyCode>,
keymap: HashMap<KeyCode, A>,
pressed_actions: HashSet<A>,
pressed_actions_once: HashSet<A>,
mouse_delta: (f64, f64),
}
impl<A: Copy + Eq + Hash> Input<A> {
pub fn new() -> Self {
Self {
pressed_keys: HashSet::new(),
pressed_once: HashSet::new(),
keymap: HashMap::new(),
pressed_actions: HashSet::new(),
pressed_actions_once: HashSet::new(),
mouse_delta: (0.0, 0.0),
}
}
pub fn map_key(&mut self, key: KeyCode, action: A) {
self.keymap.insert(key, action);
}
pub fn clear_keymap(&mut self) {
self.keymap.clear();
self.pressed_actions.clear();
self.pressed_actions_once.clear();
}
pub fn handle_event<T>(&mut self, event: &Event<T>) {
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::KeyboardInput { event, .. } => {
let key_code = match event.physical_key {
PhysicalKey::Code(code) => code,
_ => return,
};
match event.state {
ElementState::Pressed => {
self.pressed_keys.insert(key_code);
self.pressed_once.insert(key_code);
if let Some(&action) = self.keymap.get(&key_code) {
self.pressed_actions.insert(action);
self.pressed_actions_once.insert(action);
}
}
ElementState::Released => {
self.pressed_keys.remove(&key_code);
if let Some(&action) = self.keymap.get(&key_code) {
self.pressed_actions.remove(&action);
}
}
}
}
_ => {}
},
Event::DeviceEvent { event, .. } => match event {
DeviceEvent::MouseMotion { delta } => {
self.mouse_delta.0 += delta.0;
self.mouse_delta.1 += delta.1;
}
_ => {}
},
_ => {}
}
}
pub fn key_held(&self, key: KeyCode) -> bool {
self.pressed_keys.contains(&key)
}
pub fn key_pressed(&self, key: KeyCode) -> bool {
self.pressed_once.contains(&key)
}
pub fn action_held(&self, action: A) -> bool {
self.pressed_actions.contains(&action)
}
pub fn action_pressed(&self, action: A) -> bool {
self.pressed_actions_once.contains(&action)
}
pub fn mouse_delta(&self) -> (f64, f64) {
self.mouse_delta
}
pub fn end_frame(&mut self) {
self.mouse_delta = (0.0, 0.0);
self.pressed_once.clear();
self.pressed_actions_once.clear();
}
}