use crate::GameState; use crate::player::toolbar::Item; use crate::player::{Player, PlayerAction}; use crate::util::{single, single_mut}; use bevy::{prelude::*, window::PrimaryWindow}; use bevy_egui::{EguiContexts, EguiPlugin, egui}; use bevy_rapier3d::prelude::*; use bevy_rapier3d::rapier::prelude::CollisionEventFlags; use std::iter; use super::Interact; pub(super) fn plugin(app: &mut App) { app.add_plugins(EguiPlugin) .init_resource::() .add_systems( Update, ( update_interaction_opportunities, display_interaction_prompt, handle_pick_up, ) .chain() .run_if(in_state(GameState::Playing)), ); } #[derive(Debug, Clone, Eq, PartialEq, Resource, Default)] struct InteractionOpportunity(Option); fn update_interaction_opportunities( mut collision_events: EventReader, player_query: Query>, parents: Query<&Parent>, target_query: Query, With)>, mut interaction_opportunity: ResMut, ) { let player = single!(player_query); for event in collision_events.read() { dbg!(event); let (e1, e2, started) = match event { CollisionEvent::Started(e1, e2, CollisionEventFlags::SENSOR) => (*e1, *e2, true), CollisionEvent::Stopped(e1, e2, CollisionEventFlags::SENSOR) => (*e1, *e2, false), _ => { continue; } }; let poss_target = match player { p if p == e1 => e2, p if p == e2 => e1, _ => continue, }; let mut ancestors = iter::once(poss_target).chain(parents.iter_ancestors(poss_target)); let Some(target) = ancestors.find_map(|entity| target_query.get(entity).ok()) else { continue; }; if started { interaction_opportunity.0.replace(target); } else { interaction_opportunity.0.take_if(|t| *t == target); } } } fn display_interaction_prompt( interaction_opportunity: Res, mut egui_contexts: EguiContexts, primary_windows: Query<&Window, With>, names: Query<&Name, With>, // only the interactables ofcourse ) { let Some(opportunity) = interaction_opportunity.0 else { return; }; let window = single!(primary_windows); let entity_name = names .get(opportunity) .map(|name| name.as_str()) .expect("A named Interactable object"); egui::Window::new("Interaction") .collapsible(false) .title_bar(false) .auto_sized() .fixed_pos(egui::Pos2::new(window.width() / 2., window.height() / 2.)) .show(egui_contexts.ctx_mut(), |ui| { ui.label(format!("E: Pick Up {entity_name}")); }); } fn handle_pick_up( // current action mut action: Query<(&PlayerAction, &mut Item), With>, // current interactable interaction_opportunity: Res, ) { let Some(target) = interaction_opportunity.0 else { return; }; let (action, mut item) = single_mut!(action); if *action == PlayerAction::Interact { let _replaced = item.set_item(target); } }