From 350fddc2af061979b15a6eae2c6dd8fc91d853b8 Mon Sep 17 00:00:00 2001 From: Jonas H Date: Thu, 5 Mar 2026 15:05:49 +0100 Subject: [PATCH] trigger system --- src/components/mod.rs | 2 + src/components/trigger.rs | 37 ++++++++++++++++++ src/main.rs | 2 + src/systems/mod.rs | 5 +++ src/systems/trigger.rs | 82 +++++++++++++++++++++++++++++++++++++++ src/world.rs | 6 +++ 6 files changed, 134 insertions(+) create mode 100644 src/components/trigger.rs create mode 100644 src/systems/trigger.rs diff --git a/src/components/mod.rs b/src/components/mod.rs index 1722881..6469300 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -10,6 +10,7 @@ pub mod noclip; pub mod physics; pub mod rotate; pub mod tree_instances; +pub mod trigger; pub use camera::CameraComponent; pub use dissolve::DissolveComponent; @@ -21,3 +22,4 @@ pub use movement::MovementComponent; pub use physics::PhysicsComponent; pub use rotate::RotateComponent; pub use tree_instances::TreeInstancesComponent; +pub use trigger::{TriggerComponent, TriggerEvent, TriggerEventKind, TriggerFilter, TriggerShape, TriggerState}; diff --git a/src/components/trigger.rs b/src/components/trigger.rs new file mode 100644 index 0000000..c9571c6 --- /dev/null +++ b/src/components/trigger.rs @@ -0,0 +1,37 @@ +use crate::entity::EntityHandle; + +pub enum TriggerShape +{ + Sphere { radius: f32 }, +} + +pub enum TriggerFilter +{ + Player, +} + +pub enum TriggerState +{ + Idle, + Inside, +} + +pub struct TriggerComponent +{ + pub shape: TriggerShape, + pub filter: TriggerFilter, + pub state: TriggerState, +} + +pub enum TriggerEventKind +{ + Entered, + Exited, +} + +pub struct TriggerEvent +{ + pub trigger_entity: EntityHandle, + pub activator_entity: EntityHandle, + pub kind: TriggerEventKind, +} diff --git a/src/main.rs b/src/main.rs index 095647d..f0d514c 100755 --- a/src/main.rs +++ b/src/main.rs @@ -41,6 +41,7 @@ use crate::systems::{ camera_follow_system, camera_input_system, camera_view_matrix, physics_sync_system, player_input_system, render_system, rotate_system, snow_system, spotlight_sync_system, start_camera_following, state_machine_physics_system, state_machine_system, + trigger_system, }; use crate::systems::camera::stop_camera_following; use crate::utility::time::Time; @@ -283,6 +284,7 @@ fn main() -> Result<(), Box> PhysicsManager::physics_step(); physics_sync_system(&mut world); + trigger_system(&mut world); physics_accumulator -= FIXED_TIMESTEP; } diff --git a/src/systems/mod.rs b/src/systems/mod.rs index 42d1952..bcf4afe 100644 --- a/src/systems/mod.rs +++ b/src/systems/mod.rs @@ -9,6 +9,7 @@ pub mod snow; pub mod spotlight_sync; pub mod state_machine; pub mod tree_dissolve; +pub mod trigger; pub use camera::{ camera_follow_system, camera_input_system, camera_noclip_system, camera_view_matrix, @@ -21,3 +22,7 @@ pub use rotate::rotate_system; pub use snow::snow_system; pub use spotlight_sync::spotlight_sync_system; pub use state_machine::{state_machine_physics_system, state_machine_system}; +pub use tree_dissolve::{ + tree_dissolve_update_system, tree_instance_buffer_update_system, tree_occlusion_system, +}; +pub use trigger::trigger_system; diff --git a/src/systems/trigger.rs b/src/systems/trigger.rs new file mode 100644 index 0000000..42f45d8 --- /dev/null +++ b/src/systems/trigger.rs @@ -0,0 +1,82 @@ +use glam::Vec3; + +use crate::components::trigger::{TriggerEvent, TriggerEventKind, TriggerFilter, TriggerShape, TriggerState}; +use crate::entity::EntityHandle; +use crate::world::World; + +pub fn trigger_system(world: &mut World) +{ + world.trigger_events.clear(); + + let trigger_entities: Vec = world.triggers.all(); + let mut pending_events: Vec = Vec::new(); + + for trigger_entity in trigger_entities + { + let trigger_pos = match world.transforms.get(trigger_entity) + { + Some(t) => t.position, + None => continue, + }; + + let candidate_entities: Vec = match world.triggers.get(trigger_entity) + { + Some(trigger) => match &trigger.filter + { + TriggerFilter::Player => world.player_tags.all(), + }, + None => continue, + }; + + let activator_positions: Vec<(EntityHandle, Vec3)> = candidate_entities + .into_iter() + .filter_map(|e| world.transforms.get(e).map(|t| (e, t.position))) + .collect(); + + let overlapping = match world.triggers.get(trigger_entity) + { + Some(trigger) => activator_positions.iter().any(|(_, pos)| match &trigger.shape + { + TriggerShape::Sphere { radius } => (trigger_pos - *pos).length() < *radius, + }), + None => continue, + }; + + let first_activator = activator_positions.first().map(|(e, _)| *e); + + if let Some(trigger) = world.triggers.get_mut(trigger_entity) + { + match (&trigger.state, overlapping) + { + (TriggerState::Idle, true) => + { + trigger.state = TriggerState::Inside; + if let Some(activator_entity) = first_activator + { + pending_events.push(TriggerEvent { + trigger_entity, + activator_entity, + kind: TriggerEventKind::Entered, + }); + } + } + (TriggerState::Inside, false) => + { + trigger.state = TriggerState::Idle; + if let Some(activator_entity) = first_activator + { + pending_events.push(TriggerEvent { + trigger_entity, + activator_entity, + kind: TriggerEventKind::Exited, + }); + } + } + _ => + {} + } + } + } + + world.trigger_events.extend(pending_events); +} diff --git a/src/world.rs b/src/world.rs index 641760f..9bc9722 100644 --- a/src/world.rs +++ b/src/world.rs @@ -4,6 +4,7 @@ use crate::components::dissolve::DissolveComponent; use crate::components::follow::FollowComponent; use crate::components::lights::spot::SpotlightComponent; use crate::components::tree_instances::TreeInstancesComponent; +use crate::components::trigger::{TriggerComponent, TriggerEvent}; use crate::components::{ CameraComponent, InputComponent, JumpComponent, MeshComponent, MovementComponent, PhysicsComponent, RotateComponent, @@ -86,6 +87,8 @@ pub struct World pub rotates: Storage, pub tree_instances: Storage, pub names: Storage, + pub triggers: Storage, + pub trigger_events: Vec, } impl World @@ -110,6 +113,8 @@ impl World rotates: Storage::new(), tree_instances: Storage::new(), names: Storage::new(), + triggers: Storage::new(), + trigger_events: Vec::new(), } } @@ -136,6 +141,7 @@ impl World self.rotates.remove(entity); self.tree_instances.remove(entity); self.names.remove(entity); + self.triggers.remove(entity); self.entities.despawn(entity); }