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); }