bevy_tnua/
lib.rs

1//! # Tnua - A Character Controller for Bevy.
2//!
3//! Tnua ("motion" in Hebrew) is a floating character controller, which means that instead of
4//! constantly touching the ground the character floats above it, which makes many aspects of the
5//! motion control simpler.
6//!
7//! Tnua can use [Rapier](https://rapier.rs/) or [Avian](https://github.com/Jondolf/avian), and
8//! supports both the 2D and 3D versions of both with integration crates:
9//!
10//! * For Rapier 2D, add the [bevy-tnua-rapier2d](https://crates.io/crates/bevy-tnua-rapier2d) crate.
11//! * For Rapier 3D, add the [bevy-tnua-rapier3d](https://crates.io/crates/bevy-tnua-rapier3d) crate.
12//! * For Avian 2D, add the [bevy-tnua-avian2d](https://crates.io/crates/bevy-tnua-avian2d) crate.
13//! * For Avian 3D, add the [bevy-tnua-avian3d](https://crates.io/crates/bevy-tnua-avian3d) crate.
14//! * Third party integration crates. Such crates should depend on
15//!   [bevy-tnua-physics-integration-layer](https://crates.io/crates/bevy-tnua-physics-integration-layer)
16//!   and not the main bevy-tnua crate.
17//!
18//! Each physics integration crate has basic usage instructions for adding it in its documentation.
19//!
20//! When using a physics backend with double precision (like Avian with the `f64` flag), the `f64`
21//! flag should be added to all the Tnua crates. This applies to double precision data that gets
22//! defined by the physics backend - Bevy itself will still use single precision, and this is the
23//! precision the position and rotation will use.
24//!
25//! In addition to the physics integration plugin, the
26//! [`TnuaControllerPlugin`](prelude::TnuaControllerPlugin) should also be added.
27//!
28//! Some physics backends support running in different schedules (e.g. `FixedUpdate` to make the
29//! simulation deterministic). When using this feature, the physics integration plugin,
30//! `TnuaControllerPlugin`, and any other Tnua plugin that supports it (such as
31//! [`TnuaCrouchEnforcer`](crate::control_helpers::TnuaCrouchEnforcer)) must also be registered in
32//! that schedule, using their `::new()` method instead of `::default()`. The player controls
33//! systems must also be registered under that same schedule (instead of under `Update`, which is
34//! where it should usually be registered)
35//!
36//! A Tnua controlled character must have a dynamic rigid body, everything from
37//! `Tnua<physics-backend>IOBundle` (e.g. - for Rapier 3D, use `TnuaRapier3dIOBundle`), and a
38//! [`TnuaController`](prelude::TnuaController) (and its automatically added required component):
39//! ```no_run
40//! # use bevy::prelude::*;
41//! # // Not importing from Rapier because there are two versions and the default features does not
42//! # // enable either:
43//! # type TnuaRapier3dIOBundle = ();
44//! # #[derive(Component)]
45//! # enum RigidBody { Dynamic }
46//! # use bevy_tnua::prelude::*;
47//! # let mut commands: Commands = panic!();
48//! # let mut cmd = commands.spawn_empty();
49//! cmd.insert(RigidBody::Dynamic);
50//! cmd.insert(TnuaRapier3dIOBundle::default()); // this one depends on the physics backend
51//! cmd.insert(TnuaController::default());
52//! ```
53//! Typically though it'd also include a `Collider`.
54//!
55//! ## Optional But Recommended
56//!
57//! * Tnua, by default, casts a single ray to the ground. This can be a problem when the character
58//!   stands on a ledge, because the ray may be past the ledge while the character's collider
59//!   isn't. To avoid that, use `Tnua<physics-backend>SensorShape` (e.g. - for Rapier 3D, use
60//!   `TnuaRapier3dSensorShape`) to replace the ray with a shape that resembles the collider. It is
61//!   better to use a shape a little bit smaller than the collider, so that when the character
62//!   presses against a wall Tnua won't think it should be lifted up when the casted shape hits
63//!   that wall.
64//! * Tnua will apply forces to keep the character upright, but it is also possible to lock
65//!   rotation so that there would be no tilting at all. This is done by Tnua itself - it has to be
66//!   done by the physics engine. Both Rapier and Avian can do it using a component called
67//!   `LockedAxes`. When using it in 3D in combination of rotation controls (such as
68//!   [`TnuaBuiltinWalk::desired_forward`](builtins::TnuaBuiltinWalk::desired_forward)) make sure
69//!   to only lock the X and Z axess, so that Tnua could rotate the character around the Y axis.
70//!
71//! ## Controlling the Character
72//!
73//! To control the character, update the [`TnuaController`](prelude::TnuaController) by feeding it
74//! a [basis](TnuaBasis) and zero or more [actions](TnuaAction). For some of the advanced features
75//! to work, the system that does this needs to be placed inside the [`TnuaUserControlsSystemSet`]
76//! system set.
77//!
78//! ```no_run
79//! # use bevy::prelude::*;
80//! # use bevy_tnua::prelude::*;
81//! # use bevy_tnua::math::Vector3;
82//! # #[derive(Component)]
83//! # struct PlayerInputComponent;
84//! # impl PlayerInputComponent {
85//! # fn direction_vector(&self) -> Vector3 { Vector3::ZERO }
86//! # fn jump_pressed(&self) -> bool { false }
87//! # }
88//! fn player_control_system(mut query: Query<(
89//!     &mut TnuaController,
90//!     &PlayerInputComponent,  // not part of Tnua - defined in user code
91//! )>) {
92//!     for (mut controller, player_input) in query.iter_mut() {
93//!         controller.basis(TnuaBuiltinWalk {
94//!             // Move in the direction the player entered, at a speed of 10.0:
95//!             desired_velocity: player_input.direction_vector() * 10.0,
96//!
97//!             // Turn the character in the movement direction:
98//!             desired_forward: Dir3::new(player_input.direction_vector()).ok(),
99//!             
100//!             // Must be larger than the height of the entity's center from the bottom of its
101//!             // collider, or else the character will not float and Tnua will not work properly:
102//!             float_height: 2.0,
103//!
104//!             // TnuaBuiltinWalk has many other fields that can be configured:
105//!             ..Default::default()
106//!         });
107//!
108//!         if player_input.jump_pressed() {
109//!             // The jump action must be fed as long as the player holds the button.
110//!             controller.action(TnuaBuiltinJump {
111//!                 // The full height of the jump, if the player does not release the button:
112//!                 height: 4.0,
113//!
114//!                 // TnuaBuiltinJump too has other fields that can be configured:
115//!                 ..Default::default()
116//!             });
117//!         }
118//!     }
119//! }
120//! ```
121//! Refer to the documentation of [`TnuaController`](prelude::TnuaController) for more information,
122//! but essentially the _basis_ controls the general movement and the _action_ is something
123//! special (jump, dash, crouch, etc.)
124//!
125//! ## Motion Based Animation
126//!
127//! [`TnuaController`](crate::prelude::TnuaController) can also be used to retreive data that can
128//! be used to decide which animation to play. A useful helper for that is [`TnuaAnimatingState`].
129mod animating_helper;
130mod basis_action_traits;
131pub mod builtins;
132pub mod control_helpers;
133pub mod controller;
134pub mod radar_lens;
135pub mod util;
136pub use animating_helper::{TnuaAnimatingState, TnuaAnimatingStateDirective};
137pub use basis_action_traits::{
138    DynamicAction, DynamicBasis, TnuaAction, TnuaActionContext, TnuaActionInitiationDirective,
139    TnuaActionLifecycleDirective, TnuaActionLifecycleStatus, TnuaBasis, TnuaBasisContext,
140};
141
142pub mod prelude {
143    pub use crate::builtins::{TnuaBuiltinJump, TnuaBuiltinWalk};
144    pub use crate::controller::{TnuaController, TnuaControllerPlugin};
145    pub use crate::{TnuaAction, TnuaPipelineStages, TnuaUserControlsSystemSet};
146}
147
148pub use bevy_tnua_physics_integration_layer::data_for_backends::*;
149pub use bevy_tnua_physics_integration_layer::*;
150
151use bevy::prelude::*;
152
153/// The user controls should be applied in this system set.
154#[derive(SystemSet, Clone, PartialEq, Eq, Debug, Hash)]
155pub struct TnuaUserControlsSystemSet;