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
//! # Physics Integration Layer for bevy-tnua
//!
//! Crates that implement a physics layer integration for Tnua (like bevy-tnua-rapier or
//! bevy-tnua-avian) should depend on this crate and not on the main bevy-tnua crate. This crate
//! should update less often - only when there are changes in the integration layer (which is not
//! supposed to change as much) or when Bevy itself updates.
//!
//! To integrate a Bevy physics engine with Tnua, one should create a plugin named
//! `Tnua<physics-engine-name>Plugin`, which:
//!
//! * Configures [`TnuaSystemSet`] to not run when the physics engine is paused.
//! * Add systems, to the [`TnuaPipelineStages::Sensors`] stage, that update:
//!   * [`TnuaRigidBodyTracker`](data_for_backends::TnuaRigidBodyTracker) with the objects current
//!     kinematic status (position, rotation, velocity, angular velocity) as well as the gravity
//!     currently applied to it.
//!   * [`TnuaProximitySensor`](data_for_backends::TnuaProximitySensor) with the _first_ tangible
//!     collider within range, and [`TnuaGhostSensor`](data_for_backends::TnuaGhostSensor) with
//!     _all_ the ghost colliders found before that tangible collider.
//!     * A tangible collider is a **non-ghost** collider that physically interacts with the
//!       character's collider.
//!     * A ghost collider is a collider marked with the
//!       [`TnuaGhostPlatform`](data_for_backends::TnuaGhostPlatform) component. It may or may not
//!       physically interact with the character's collider - as long as it has the component it is
//!       considered a ghost collider.
//!     * The sensor should ignore the owner entity's collider.
//!     * If the sensor has the
//!       [`TnuaSubservientSensor`](subservient_sensors::TnuaSubservientSensor) component, the
//!       "owner entity" is defined as the `owner_entity` field from that component and not the
//!       entity the sensor component is attached to.
//!     * The detection should be done with a ray cast, unless the sensor is configured to cast a
//!       shape instead. Such configuration is done with component, defined by the integration
//!       crate, that specifies the shape to cast in a way the integration crate can pass on to the
//!       physics engine. The name of that component should be
//!       `Tnua<physics-engine-name>SensorShape`.
//!
//!   The integration crate may update all these components in one system or multiple systems as it
//!   sees fit.
//!
//! * Add a system, to the [`TnuaPipelineStages::Motors`] stage, that applies all the impulses and
//!   accelerations from [`TnuaMotor`](data_for_backends::TnuaMotor) components.
//!
//!   Here, too, if it makes sense to split this work into multiple systems the integration crate
//!   may do so at its own discretion.
//!
//! * Ensure that [`TnuaSystemSet`] runs before the integration backend's systems.
//!
//! The integration backend's systems must run with the same timing as the physics backend. If the
//! physics backend supports running in a different schedule, the integration plugin should also
//! support it by adding a `::new()` method that accepts a schedule and registers all the systems
//! there. It should also implement `Default` to make it run in the default schedule (usually
//! `Update`)
//!
//! Note that a physics backend may run its systems under `PostUpdate` instead of `Update` (both
//! Rapier and Avian do this by default). In this case, it's still okay for the integration backend
//! to run under `Update`, because they use the same timing.
//!
//! If the integration crate needs the character entity to have more components from the physics
//! engine crate, that one would not naturally add to it, it should define a bundle named
//! `Tnua<physics-engine-name>IOBundle` that adds these components. One would naturally add a rigid
//! body and a collider, so they should not go in that bundle, but if the crate needs things users
//! rarely think about - for example, bevy_rapier's `ReadMassProperties` - then these components
//! should go in that bundle.
use bevy::prelude::*;

pub mod data_for_backends;
pub mod math;
pub mod subservient_sensors;

/// Umbrella system set for [`TnuaPipelineStages`].
///
/// The physics backends' plugins are responsible for preventing this entire system set from
/// running when the physics backend itself is paused.
#[derive(SystemSet, Clone, PartialEq, Eq, Debug, Hash)]
pub struct TnuaSystemSet;

/// The various stages of the Tnua pipeline.
#[derive(SystemSet, Clone, PartialEq, Eq, Debug, Hash)]
pub enum TnuaPipelineStages {
    /// Data is read from the physics backend.
    Sensors,
    /// Data is propagated through the subservient sensors.
    SubservientSensors,
    /// Tnua decieds how the entity should be manipulated.
    Logic,
    /// Forces are applied in the physics backend.
    Motors,
}