Thu Nov 21 12:17:08 PM EST 2024
This commit is contained in:
parent
85c8056166
commit
57827d5371
@ -6,7 +6,7 @@ use bevy::{prelude::*, utils::HashSet};
|
|||||||
///
|
///
|
||||||
/// An entity with an `Interactor` component can be passed to an `InteractorFiredEvent` in order to
|
/// An entity with an `Interactor` component can be passed to an `InteractorFiredEvent` in order to
|
||||||
/// start an interaction with any nearby `Interactable` entities.
|
/// start an interaction with any nearby `Interactable` entities.
|
||||||
#[derive(Component, Default)]
|
#[derive(Component, Default, Debug)]
|
||||||
pub struct Interactor {
|
pub struct Interactor {
|
||||||
/// All `Interactable` targets in-range of this interactor.
|
/// All `Interactable` targets in-range of this interactor.
|
||||||
pub targets: HashSet<Entity>,
|
pub targets: HashSet<Entity>,
|
||||||
@ -18,10 +18,19 @@ pub struct Interactor {
|
|||||||
///
|
///
|
||||||
/// An entity with an `Interactable` component might get passed to an `InteractionEvent` when an
|
/// An entity with an `Interactable` component might get passed to an `InteractionEvent` when an
|
||||||
/// `Interactor` requests an interaction, if the interactable is in range.
|
/// `Interactor` requests an interaction, if the interactable is in range.
|
||||||
#[derive(Component)]
|
#[derive(Component, Clone, Debug)]
|
||||||
pub struct Interactable {
|
pub struct Interactable {
|
||||||
|
/// An optional name for this interactable
|
||||||
|
pub name: Option<String>,
|
||||||
|
/// An optional description of the action
|
||||||
|
pub description: Option<String>,
|
||||||
|
/// Predicate to check to see if interaction is possible
|
||||||
|
pub predicate: Option<fn(Entity, &mut World) -> bool>,
|
||||||
pub(crate) exclusive: bool,
|
pub(crate) exclusive: bool,
|
||||||
pub(crate) max_distance_squared: f32,
|
pub(crate) max_distance_squared: f32,
|
||||||
|
pub(crate) possible: bool,
|
||||||
|
/// Whether this pickup is enabled
|
||||||
|
pub enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interactable {
|
impl Interactable {
|
||||||
@ -30,17 +39,27 @@ impl Interactable {
|
|||||||
/// If exclusive, this interactable will only be interacted with if it's the closest one to the
|
/// If exclusive, this interactable will only be interacted with if it's the closest one to the
|
||||||
/// interactor, and the interaction will *not* be processed for any other in-range
|
/// interactor, and the interaction will *not* be processed for any other in-range
|
||||||
/// interactables.
|
/// interactables.
|
||||||
pub fn new(max_distance: f32, exclusive: bool) -> Self {
|
pub fn new(max_distance: f32, exclusive: bool, name: Option<String>, description: Option<String>, predicate: Option<fn(Entity, &mut World) -> bool>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
predicate,
|
||||||
exclusive,
|
exclusive,
|
||||||
max_distance_squared: max_distance * max_distance,
|
max_distance_squared: max_distance * max_distance,
|
||||||
|
possible: true,
|
||||||
|
enabled: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets whether this interaction is currently possible. Set this value using predicate.
|
||||||
|
pub fn possible(&self) -> bool {
|
||||||
|
self.possible
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Interactable {
|
impl Default for Interactable {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new(1.0, false)
|
Self::new(1.0, false, None, None, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
37
src/lib.rs
37
src/lib.rs
@ -26,9 +26,12 @@ pub struct InteractionPlugin;
|
|||||||
|
|
||||||
impl Plugin for InteractionPlugin {
|
impl Plugin for InteractionPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(Update, (handle_interactor_events, update_interactor_targets))
|
app.add_systems(
|
||||||
.add_event::<InteractorFiredEvent>()
|
Update,
|
||||||
.add_event::<InteractionEvent>();
|
(handle_interactor_events, update_interactor_targets, update_interactable_predicates),
|
||||||
|
)
|
||||||
|
.add_event::<InteractorFiredEvent>()
|
||||||
|
.add_event::<InteractionEvent>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +46,7 @@ fn handle_interactor_events(
|
|||||||
|
|
||||||
if let Some(interactable_entity) = interactor.closest {
|
if let Some(interactable_entity) = interactor.closest {
|
||||||
let interactable = interactable_query.get(interactable_entity).unwrap();
|
let interactable = interactable_query.get(interactable_entity).unwrap();
|
||||||
if interactable.exclusive {
|
if interactable.exclusive && interactable.possible {
|
||||||
event_writer.send(InteractionEvent {
|
event_writer.send(InteractionEvent {
|
||||||
interactor: *interactor_entity,
|
interactor: *interactor_entity,
|
||||||
interactable: interactable_entity,
|
interactable: interactable_entity,
|
||||||
@ -52,7 +55,7 @@ fn handle_interactor_events(
|
|||||||
} else {
|
} else {
|
||||||
for interactable_entity in &interactor.targets {
|
for interactable_entity in &interactor.targets {
|
||||||
let interactable = interactable_query.get(*interactable_entity).unwrap();
|
let interactable = interactable_query.get(*interactable_entity).unwrap();
|
||||||
if !interactable.exclusive {
|
if !interactable.exclusive && interactable.possible {
|
||||||
event_writer.send(InteractionEvent {
|
event_writer.send(InteractionEvent {
|
||||||
interactor: *interactor_entity,
|
interactor: *interactor_entity,
|
||||||
interactable: *interactable_entity,
|
interactable: *interactable_entity,
|
||||||
@ -73,7 +76,11 @@ fn update_interactor_targets(
|
|||||||
let interactor_transform = transform_query.get(interactor_entity).unwrap();
|
let interactor_transform = transform_query.get(interactor_entity).unwrap();
|
||||||
|
|
||||||
let mut closest_active_interactable: Option<(f32, Entity)> = None;
|
let mut closest_active_interactable: Option<(f32, Entity)> = None;
|
||||||
|
interactor.targets.clear();
|
||||||
for (interactable_entity, interactable) in interactable_query.iter_mut() {
|
for (interactable_entity, interactable) in interactable_query.iter_mut() {
|
||||||
|
if !interactable.enabled {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let interactable_transform = transform_query.get(interactable_entity).unwrap();
|
let interactable_transform = transform_query.get(interactable_entity).unwrap();
|
||||||
let interactable_distance_squared = interactable_transform
|
let interactable_distance_squared = interactable_transform
|
||||||
.translation()
|
.translation()
|
||||||
@ -85,7 +92,7 @@ fn update_interactor_targets(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
if interactable_distance_squared < interactable.max_distance_squared
|
if interactable_distance_squared < interactable.max_distance_squared
|
||||||
&& interactable_arccosine < PI / 8.0
|
&& interactable_arccosine < PI / 4.0
|
||||||
{
|
{
|
||||||
interactor.targets.insert(interactable_entity);
|
interactor.targets.insert(interactable_entity);
|
||||||
if let Some((arccosine, _)) = closest_active_interactable {
|
if let Some((arccosine, _)) = closest_active_interactable {
|
||||||
@ -97,8 +104,6 @@ fn update_interactor_targets(
|
|||||||
closest_active_interactable =
|
closest_active_interactable =
|
||||||
Some((interactable_arccosine, interactable_entity));
|
Some((interactable_arccosine, interactable_entity));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
interactor.targets.remove(&interactable_entity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
interactor.closest = if let Some((_, interactable_entity)) = closest_active_interactable {
|
interactor.closest = if let Some((_, interactable_entity)) = closest_active_interactable {
|
||||||
@ -108,3 +113,19 @@ fn update_interactor_targets(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_interactable_predicates(world: &mut World) {
|
||||||
|
let mut interactable_query = world.query::<(Entity, &mut Interactable)>();
|
||||||
|
let mut interactables = vec![];
|
||||||
|
for (interactable_entity, interactable) in interactable_query.iter(world) {
|
||||||
|
interactables.push((interactable_entity, (*interactable).clone()));
|
||||||
|
}
|
||||||
|
for (interactable_entity, interactable) in interactables.iter_mut() {
|
||||||
|
if let Some(predicate) = &interactable.predicate {
|
||||||
|
interactable.possible = predicate(*interactable_entity, world);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ((_, mut interactable), (_, temp)) in interactable_query.iter_mut(world).zip(interactables.into_iter()) {
|
||||||
|
*interactable = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user