Giant refactor for a better event-driven architecture

This commit is contained in:
reo 2025-07-21 23:52:32 +03:00
parent 341d531db3
commit 88a21040cd
22 changed files with 936 additions and 67 deletions

View file

@ -5,4 +5,7 @@ edition = "2021"
[dependencies]
winit = "0.30"
glam = "0.30.4"
glam = "0.30.4"
hecs = "0.10.5"
raidillon_core = { path = "../raidillon_core" }
raidillon_render = { path = "../raidillon_render" }

View file

@ -0,0 +1,109 @@
use hecs::{Entity, World};
use raidillon_core::{EventHandler, GameEvent, InputAction, System, AssetManager, Model, Material, EventBus};
use raidillon_render::Camera;
use crate::FPSCameraController;
use glam::Vec3;
pub struct CameraSystem {
controller: FPSCameraController,
camera_entity: Entity,
yaw: f32,
pitch: f32,
}
impl CameraSystem {
pub fn new(camera_entity: Entity) -> Self {
Self {
controller: FPSCameraController::new(Vec3::new(0.0, 0.0, 2.0)),
camera_entity,
yaw: -90.0,
pitch: 0.0,
}
}
pub fn update(&mut self, world: &mut World, dt: f32, mouse_delta: (f64, f64)) {
// Apply mouse movement if there's any
if mouse_delta.0 != 0.0 || mouse_delta.1 != 0.0 {
self.yaw += mouse_delta.0 as f32 * self.controller.sensitivity;
self.pitch -= mouse_delta.1 as f32 * self.controller.sensitivity;
self.pitch = self.pitch.clamp(-89.0, 89.0);
// Update front vector based on new yaw/pitch
let yaw_rad = self.yaw.to_radians();
let pitch_rad = self.pitch.to_radians();
let front = Vec3::new(
yaw_rad.cos() * pitch_rad.cos(),
pitch_rad.sin(),
yaw_rad.sin() * pitch_rad.cos(),
).normalize();
}
// Update camera component in the world
if let Ok(cam) = world.query_one_mut::<&mut Camera>(self.camera_entity) {
cam.eye = self.controller.position;
cam.center = self.controller.position + self.controller.front();
}
}
pub fn handle_input_action(&mut self, action: InputAction, dt: f32) {
let front = self.controller.front();
let right = front.cross(Vec3::Y).normalize();
let frame_speed = self.controller.speed * dt;
match action {
InputAction::MoveForward => {
self.controller.position += front * frame_speed;
}
InputAction::MoveBackward => {
self.controller.position -= front * frame_speed;
}
InputAction::MoveLeft => {
self.controller.position -= right * frame_speed;
}
InputAction::MoveRight => {
self.controller.position += right * frame_speed;
}
}
}
pub fn resize_camera(&mut self, world: &mut World, width: u32, height: u32) {
if let Ok(cam) = world.query_one_mut::<&mut Camera>(self.camera_entity) {
cam.aspect = width as f32 / height as f32;
}
}
}
impl EventHandler for CameraSystem {
fn handle(&mut self, event: &GameEvent) {
match event {
GameEvent::InputAction(_action) => {
// Movement will be handled separately with delta time
// This is just for event registration
}
GameEvent::WindowResize { width: _, height: _ } => {
// Window resize will be handled separately with world access
}
_ => {}
}
}
}
impl System for CameraSystem {
fn update(&mut self, world: &mut World, _resources: &AssetManager<dyn Model, dyn Material>, _events: &mut EventBus, _dt: f32) {
// Camera update logic is handled separately with mouse input
// This system mainly responds to events
}
fn handle_event(&mut self, event: &GameEvent, world: &mut World) {
match event {
GameEvent::WindowResize { width, height } => {
self.resize_camera(world, *width, *height);
}
_ => {}
}
}
fn name(&self) -> &'static str {
"CameraSystem"
}
}

View file

@ -0,0 +1,64 @@
use raidillon_core::{EventBus, GameEvent, InputAction, System, AssetManager, Model, Material};
use crate::Input;
use hecs::World;
pub struct InputSystem {
input: Input<InputAction>,
}
impl InputSystem {
pub fn new() -> Self {
let mut input = Input::<InputAction>::new();
input.map_key(winit::keyboard::KeyCode::KeyW, InputAction::MoveForward);
input.map_key(winit::keyboard::KeyCode::KeyS, InputAction::MoveBackward);
input.map_key(winit::keyboard::KeyCode::KeyA, InputAction::MoveLeft);
input.map_key(winit::keyboard::KeyCode::KeyD, InputAction::MoveRight);
Self { input }
}
pub fn handle_event<T>(&mut self, event: &winit::event::Event<T>) {
self.input.handle_event(event);
}
pub fn update(&mut self, event_bus: &mut EventBus, right_mouse_held: bool) {
if right_mouse_held {
if self.input.action_held(InputAction::MoveForward) {
event_bus.emit(GameEvent::InputAction(InputAction::MoveForward));
}
if self.input.action_held(InputAction::MoveBackward) {
event_bus.emit(GameEvent::InputAction(InputAction::MoveBackward));
}
if self.input.action_held(InputAction::MoveLeft) {
event_bus.emit(GameEvent::InputAction(InputAction::MoveLeft));
}
if self.input.action_held(InputAction::MoveRight) {
event_bus.emit(GameEvent::InputAction(InputAction::MoveRight));
}
}
}
pub fn end_frame(&mut self) {
self.input.end_frame();
}
pub fn mouse_delta(&self) -> (f64, f64) {
self.input.mouse_delta()
}
}
impl System for InputSystem {
fn update(&mut self, _world: &mut World, _resources: &AssetManager<dyn Model, dyn Material>, _events: &mut EventBus, _dt: f32) {
// Input processing is handled separately in the main loop
// This system mainly generates events based on input state
}
fn handle_event(&mut self, _event: &GameEvent, _world: &mut World) {
// InputSystem doesn't need to respond to events
// It generates events based on input state
}
fn name(&self) -> &'static str {
"InputSystem"
}
}

View file

@ -5,7 +5,12 @@ use winit::event::{DeviceEvent, ElementState, Event, WindowEvent};
use winit::keyboard::{KeyCode, PhysicalKey};
pub mod camera;
pub mod input_system;
pub mod camera_system;
pub use camera::FPSCameraController;
pub use input_system::InputSystem;
pub use camera_system::CameraSystem;
pub struct Input<A: Copy + Eq + Hash> {
pressed_keys: HashSet<KeyCode>,