pub trait TnuaBasis:
Default
+ 'static
+ Send
+ Sync {
type Config: Send + Sync + Clone + Serialize + for<'de> Deserialize<'de>;
type Memory: Send + Sync + Default;
type Sensors<'a>: TnuaSensors<'a>;
// Required methods
fn apply(
&self,
config: &Self::Config,
memory: &mut Self::Memory,
sensors: &Self::Sensors<'_>,
ctx: TnuaBasisContext<'_>,
motor: &mut TnuaMotor,
);
fn get_or_create_sensors<'a: 'b, 'b>(
up_direction: Dir3,
config: &'a Self::Config,
memory: &Self::Memory,
entities: &'a mut <Self::Sensors<'static> as TnuaSensors<'static>>::Entities,
proximity_sensors_query: &'b Query<'_, '_, (&TnuaProximitySensor, Has<TnuaGhostSensor>)>,
controller_entity: Entity,
commands: &mut Commands<'_, '_>,
has_ghost_overwrites: bool,
) -> Option<Self::Sensors<'b>>;
fn ghost_sensor_overwrites<'a>(
ghost_overwrites: &'a mut <Self::Sensors<'static> as TnuaSensors<'static>>::GhostOverwrites,
entities: &<Self::Sensors<'static> as TnuaSensors<'static>>::Entities,
) -> impl Iterator<Item = (&'a mut TnuaGhostOverwrite, Entity)>;
}Expand description
The main movement command of a character.
A basis handles the character’s motion when the user is not feeding it any input, or when it
just moves around without doing anything special. A simple game would only need one basis -
TnuaBuiltinWalk - but more complex games can have bases
for things like swimming or driving.
The type that implements this trait is called the basis input, and is expected to be
overwritten each frame by the controller system of the game code. Configuration is considered
as part of the input. Configuration is stored in an asset, as part of a struct implementing
TnuaSchemeConfig which also holds the configuration for all the actions. If the basis needs
to persist data between frames it must keep it in its memory.
Required Associated Types§
type Config: Send + Sync + Clone + Serialize + for<'de> Deserialize<'de>
type Memory: Send + Sync + Default
type Sensors<'a>: TnuaSensors<'a>
Required Methods§
Sourcefn apply(
&self,
config: &Self::Config,
memory: &mut Self::Memory,
sensors: &Self::Sensors<'_>,
ctx: TnuaBasisContext<'_>,
motor: &mut TnuaMotor,
)
fn apply( &self, config: &Self::Config, memory: &mut Self::Memory, sensors: &Self::Sensors<'_>, ctx: TnuaBasisContext<'_>, motor: &mut TnuaMotor, )
This is where the basis affects the character’s motion.
This method gets called each frame to let the basis control the TnuaMotor that will
later move the character.
Note that after the motor is set in this method, if there is an action going on, the
action’s apply will also run and typically change some of the things
the basis did to the motor.
It can also update the memory.
Sourcefn get_or_create_sensors<'a: 'b, 'b>(
up_direction: Dir3,
config: &'a Self::Config,
memory: &Self::Memory,
entities: &'a mut <Self::Sensors<'static> as TnuaSensors<'static>>::Entities,
proximity_sensors_query: &'b Query<'_, '_, (&TnuaProximitySensor, Has<TnuaGhostSensor>)>,
controller_entity: Entity,
commands: &mut Commands<'_, '_>,
has_ghost_overwrites: bool,
) -> Option<Self::Sensors<'b>>
fn get_or_create_sensors<'a: 'b, 'b>( up_direction: Dir3, config: &'a Self::Config, memory: &Self::Memory, entities: &'a mut <Self::Sensors<'static> as TnuaSensors<'static>>::Entities, proximity_sensors_query: &'b Query<'_, '_, (&TnuaProximitySensor, Has<TnuaGhostSensor>)>, controller_entity: Entity, commands: &mut Commands<'_, '_>, has_ghost_overwrites: bool, ) -> Option<Self::Sensors<'b>>
This is where the basis initiates its sensors.
-
Use the helper
ProximitySensorPreparationHelperto create the sensors. -
Return
Noneif - and only if - some essential sensors are missing, because it’ll cause the controller to skip frames until it returnsSome.An example of non-essential sensor is the headroom sensor in
TnuaBuiltinWalkSensors- the controller can function without it (it just won’t be able to do crouch enforcement) so if it’s absence does not cause prevent the controller from running (unlike thegroundsensor, which is essential) -
Even if some essential sensors are missing, make sure to prepare all the sensors that need preparation before returning
None. No point preparing one sensor per frame. -
If a sensor exists but wrongly configured - launch the command to reconfigure it and return the existing sensor. Unless the configuration is totally off (e.g. - sensor points in a very wrong direction) it’s probably better to use the misconfigured one than to skip a frame.
Sourcefn ghost_sensor_overwrites<'a>(
ghost_overwrites: &'a mut <Self::Sensors<'static> as TnuaSensors<'static>>::GhostOverwrites,
entities: &<Self::Sensors<'static> as TnuaSensors<'static>>::Entities,
) -> impl Iterator<Item = (&'a mut TnuaGhostOverwrite, Entity)>
fn ghost_sensor_overwrites<'a>( ghost_overwrites: &'a mut <Self::Sensors<'static> as TnuaSensors<'static>>::GhostOverwrites, entities: &<Self::Sensors<'static> as TnuaSensors<'static>>::Entities, ) -> impl Iterator<Item = (&'a mut TnuaGhostOverwrite, Entity)>
Iterate over each ghost overwrite and the sensor entity of the relevant sensor.
Note that not all sensors need to have ghost overwrites.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.