1use crate::ghost_overrides::TnuaGhostOverwritesForBasis;
2use crate::{TnuaBasis, TnuaScheme, math::*};
3use bevy::prelude::*;
4use bevy_tnua_physics_integration_layer::data_for_backends::{
5 TnuaGhostSensor, TnuaProximitySensor, TnuaSensorOf,
6};
7
8#[derive(Component, Deref)]
12pub struct TnuaSensorsEntities<S: TnuaScheme> {
13 pub(crate) sensors_entities:
14 <<S::Basis as TnuaBasis>::Sensors<'static> as TnuaSensors<'static>>::Entities,
15}
16
17pub trait TnuaSensors<'a>: 'a + Copy + Clone {
18 type Entities: 'static + Send + Sync + Default;
19 #[cfg(feature = "serialize")]
20 type GhostOverwrites: TnuaGhostOverwritesForBasis<Entities = Self::Entities>
21 + serde::Serialize
22 + for<'de> serde::Deserialize<'de>;
23 #[cfg(not(feature = "serialize"))]
24 type GhostOverwrites: TnuaGhostOverwritesForBasis<Entities = Self::Entities>;
25}
26
27pub struct ProximitySensorPreparationHelper {
28 pub cast_origin: Vector3,
29 pub cast_direction: Dir3,
30 pub cast_shape_rotation: Quaternion,
31 pub cast_range: Float,
32 pub ghost_sensor: bool,
33}
34
35impl Default for ProximitySensorPreparationHelper {
36 fn default() -> Self {
37 Self {
38 cast_origin: Vector3::ZERO,
39 cast_direction: Dir3::NEG_Y,
40 cast_shape_rotation: Quaternion::IDENTITY,
41 cast_range: 0.0,
42 ghost_sensor: false,
43 }
44 }
45}
46
47impl ProximitySensorPreparationHelper {
48 fn already_set_in_sensor(&self, sensor: &TnuaProximitySensor) -> bool {
49 let Self {
50 cast_origin,
51 cast_direction,
52 cast_shape_rotation,
53 cast_range,
54 ghost_sensor: _,
55 } = self;
56 *cast_origin == sensor.cast_origin
57 && *cast_direction == sensor.cast_direction
58 && *cast_shape_rotation == sensor.cast_shape_rotation
59 && *cast_range == sensor.cast_range
60 }
61
62 fn to_sensor(&self) -> TnuaProximitySensor {
63 TnuaProximitySensor {
64 cast_origin: self.cast_origin,
65 cast_direction: self.cast_direction,
66 cast_shape_rotation: self.cast_shape_rotation,
67 cast_range: self.cast_range,
68 output: None,
69 }
70 }
71
72 pub fn prepare_for<'a>(
73 &self,
74 put_in_entity: &mut Option<Entity>,
75 proximity_sensors_query: &'a Query<(&TnuaProximitySensor, Has<TnuaGhostSensor>)>,
76 controller_entity: Entity,
77 commands: &mut Commands,
78 ) -> Option<&'a TnuaProximitySensor> {
79 if let Some(sensor_entity) = put_in_entity
80 && let Ok((existing_sensor, has_ghost_sensor)) =
81 proximity_sensors_query.get(*sensor_entity)
82 {
83 if !self.already_set_in_sensor(existing_sensor) {
84 commands.entity(*sensor_entity).insert(self.to_sensor());
86 }
87 if self.ghost_sensor && !has_ghost_sensor {
88 commands
89 .entity(*sensor_entity)
90 .insert(TnuaGhostSensor::default());
91 } else if !self.ghost_sensor && has_ghost_sensor {
92 commands
93 .entity(*sensor_entity)
94 .try_remove::<TnuaGhostSensor>();
95 }
96 Some(existing_sensor)
97 } else {
98 commands
99 .entity(controller_entity)
100 .with_related_entities::<TnuaSensorOf>(|commands| {
101 let mut cmd = commands.spawn(self.to_sensor());
102 if self.ghost_sensor {
103 cmd.insert(TnuaGhostSensor::default());
104 }
105 *put_in_entity = Some(cmd.id());
106 });
107 None
108 }
109 }
110
111 pub fn ensure_not_existing<'a>(
112 put_in_entity: &mut Option<Entity>,
113 proximity_sensors_query: &'a Query<(&TnuaProximitySensor, Has<TnuaGhostSensor>)>,
114 commands: &mut Commands,
115 ) -> Option<&'a TnuaProximitySensor> {
116 if let Some(sensor_entity) = put_in_entity {
117 if proximity_sensors_query.contains(*sensor_entity) {
118 commands.entity(*sensor_entity).despawn();
119 } else {
120 *put_in_entity = None;
121 }
122 }
123 None
124 }
125}