bevy_tnua/
ghost_overrides.rs

1use bevy::prelude::*;
2use bevy_tnua_physics_integration_layer::data_for_backends::TnuaProximitySensorOutput;
3
4use crate::sensor_sets::TnuaSensors;
5use crate::{TnuaBasis, TnuaScheme};
6
7/// A struct with fields of [`TnuaGhostOverwrite`] for each sensor that can have a ghost sensor.
8pub trait TnuaGhostOverwritesForBasis: 'static + Send + Sync + Default {
9    /// A struct that points to the sensor entities. Must match the entities of [the basis'
10    /// sensors](TnuaBasis::Sensors).
11    type Entities: 'static + Send + Sync + Default;
12}
13
14/// Add this component to an entity with a [`TnuaController`](crate::TnuaController) (that has the
15/// same control scheme) to generate ghost sensors and to control them.
16///
17/// This component holds and refers to a struct defined by the
18/// [`GhostOverwrites`](TnuaSensors::GhostOverwrites) of the [`Sensors`](TnuaBasis::Sensors) of the
19/// control scheme's basis. The fields of that struct should be of type [`TnuaGhostOverwrite`], and
20/// should have matching fields in the sensors' [`Entities`](TnuaSensors::Entities) (accessible via
21/// the [`TnuaSensorsEntities`](crate::TnuaSensorsEntities) component) that point to entities with
22/// a [`TnuaGhostSensor`](crate::TnuaGhostSensor) component on them that holds the ghost hits that
23/// can be set in the [`TnuaGhostOverwrite`] using its
24/// [`set`](TnuaGhostOverwrite::set) method.
25#[derive(Component, Deref, DerefMut)]
26#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
27pub struct TnuaGhostOverwrites<S: TnuaScheme>(pub <<<S as TnuaScheme>::Basis as TnuaBasis>::Sensors<'static> as TnuaSensors<'static>>::GhostOverwrites);
28
29impl<S: TnuaScheme> AsMut<
30<<<S as TnuaScheme>::Basis as TnuaBasis>::Sensors<'static> as TnuaSensors<'static>>::GhostOverwrites
31> for TnuaGhostOverwrites<S> {
32    fn as_mut(&mut self) -> &mut <<<S as TnuaScheme>::Basis as TnuaBasis>::Sensors<'static> as TnuaSensors<'static>>::GhostOverwrites {
33        &mut self.0
34    }
35}
36
37impl<S: TnuaScheme> Default for TnuaGhostOverwrites<S> {
38    fn default() -> Self {
39        Self(Default::default())
40    }
41}
42
43/// Controls how Tnua uses the ghost sensor of a single
44/// [`TnuaProximitySensor`](crate::TnuaProximitySensor).
45///
46/// Note that this is not a component because it is not stored on the sensor entity - instead it is
47/// stored with the entity that has the [`TnuaController`](crate::TnuaController) component, inside
48/// a [`TnuaGhostOverwrites`] component. The [`TnuaGhostSensor`](crate::TnuaGhostSensor) itself is
49/// stored on the sensor entity - to retrieve that [`Entity`] use the
50/// [`TnuaSensorsEntities`](crate::TnuaSensorsEntities) component.
51#[derive(Default)]
52#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
53pub struct TnuaGhostOverwrite(Option<Entity>);
54
55impl TnuaGhostOverwrite {
56    /// Set an output of the ghost sensor so that the controller will use it instead of the
57    /// (non-ghost) output of the proximity sensor.
58    ///
59    /// Note that the controller does not use that output has is - it picks an output from the
60    /// ghost sensor that matches the output provided here. This is important because the ghost
61    /// sensor will have its list of outputs refreshed before this happens.
62    ///
63    /// If set to `None`, the ghost sensor will not be used that frame and the output of the
64    /// regular proximity sensor will be used.
65    ///
66    /// The ghost overwrite will remain in place until one of the following happens:
67    /// 1. This method is invoked again - either with another output or with `None`.
68    /// 2. The ghost sensor no longer has a matching hit in its outputs list.
69    pub fn set(&mut self, sensor_output: Option<&TnuaProximitySensorOutput>) {
70        self.0 = sensor_output.map(|output| output.entity);
71    }
72
73    pub(crate) fn find_in<'a>(
74        &self,
75        ghost_outputs: &'a [TnuaProximitySensorOutput],
76    ) -> Option<&'a TnuaProximitySensorOutput> {
77        let entity = self.0?;
78        ghost_outputs.iter().find(|output| output.entity == entity)
79    }
80}