109 lines
3.3 KiB
Rust
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);
|
|
}
|
|
}
|