bevy_tnua_physics_integration_layer/obstacle_radar.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
use bevy::{prelude::*, utils::HashMap};
use crate::math::{Float, Vector3};
/// Add this to a character entity to detect obstacles around it.
///
/// Obstacles can be used for environment movement actions like climbing and wall-jumping.
///
/// This component stores rather limited data - only the detected entities and nothing about their
/// form or position. See `TnuaRadarLens` in the main Tnua crate, which wraps this with a
/// [`TnuaSpatialExt`](crate::spatial_ext::TnuaSpatialExt) to provide many helper methods for
/// running more queries on the detected obstacles.
#[derive(Component)]
pub struct TnuaObstacleRadar {
/// The radius of the radar's cylinder.
pub radius: Float,
/// The height of the radar's cylinder.
pub height: Float,
tracked_entity: Entity,
tracked_position: Vector3,
up_direction: Dir3,
blips: HashMap<Entity, BlipStatus>,
}
impl TnuaObstacleRadar {
pub fn new(radius: Float, height: Float) -> Self {
Self {
radius,
height,
tracked_entity: Entity::PLACEHOLDER,
tracked_position: Vector3::NAN,
up_direction: Dir3::Y,
blips: Default::default(),
}
}
/// Physics integration crates must call this each frame before they start calling
/// [`mark_seen`](Self::mark_seen), and feed it some general information about the character
/// entity.
pub fn pre_marking_update(
&mut self,
tracked_entity: Entity,
tracked_position: Vector3,
up_direction: Dir3,
) {
self.tracked_entity = tracked_entity;
self.tracked_position = tracked_position;
self.up_direction = up_direction;
self.blips.retain(|_, blip_status| match blip_status {
BlipStatus::Unseen => false,
BlipStatus::Seen => {
*blip_status = BlipStatus::Unseen;
true
}
});
}
/// Physics integration crates should call this for each detected entity during each frame,
/// after invoking [`pre_marking_update`](Self::pre_marking_update).
pub fn mark_seen(&mut self, entity: Entity) {
self.blips.insert(entity, BlipStatus::Seen);
}
/// Get the character entity who owns the radar (not the detected obstacle entities!)
pub fn tracked_entity(&self) -> Entity {
self.tracked_entity
}
/// Get the position of the character who owns the radar (not the detected obstacle's
/// positions!)
pub fn tracked_position(&self) -> Vector3 {
self.tracked_position
}
/// Get the direction considered up.
pub fn up_direction(&self) -> Dir3 {
self.up_direction
}
/// Iterate over all the blip entities.
pub fn iter_blips(&self) -> impl '_ + Iterator<Item = Entity> {
self.blips.keys().copied()
}
/// Check if a particular entity has been detected this frame.
pub fn has_blip(&self, entity: Entity) -> bool {
self.blips.contains_key(&entity)
}
}
pub enum BlipStatus {
Unseen,
Seen,
}