Files
among-me/src/interaction/ui.rs
LorrensP-2158466 4bd1f1343e pickup hanlder
2025-04-06 15:08:25 +02:00

109 lines
3.3 KiB
Rust

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::<InteractionOpportunity>()
.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<Entity>);
fn update_interaction_opportunities(
mut collision_events: EventReader<CollisionEvent>,
player_query: Query<Entity, With<Player>>,
parents: Query<&Parent>,
target_query: Query<Entity, (Without<Player>, With<Interact>)>,
mut interaction_opportunity: ResMut<InteractionOpportunity>,
) {
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<InteractionOpportunity>,
mut egui_contexts: EguiContexts,
primary_windows: Query<&Window, With<PrimaryWindow>>,
names: Query<&Name, With<Interact>>, // 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<Player>>,
// current interactable
interaction_opportunity: Res<InteractionOpportunity>,
) {
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);
}
}