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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#![deny(future_incompatible, nonstandard_style)]
#![warn(missing_docs, rust_2018_idioms, clippy::pedantic)]
#![allow(clippy::needless_pass_by_value, clippy::needless_doctest_main)]
#![cfg(any(dim2, dim3))]

//! An ergonomic physics API for 2d and 3d [bevy] games. (powered by [rapier])
//!
//! [bevy]: https://bevyengine.org
//!
//! [rapier]: https://rapier.rs
//!
//! # Get started
//!
//! ## Add the dependency and choose to work with either 2d or 3d
//!
//! Add the library to `Cargo.toml`.
//!
//! For a 3d game:
//! ```toml
//! heron = { version = "3", features = ["3d"] }
//! ```
//!
//! For as 2d game:
//! ```toml
//! heron = { version = "3", features = ["2d"] }
//! ```
//!
//! ### Feature flags
//!
//! One must choose to use either `2d` or `3d`. If none of theses two features is enabled, the plugin won't be available.
//!
//!
//! * `3d` Enable simulation on the 3 axes `x`, `y`, and `z`. Incompatible with the feature `2d`.
//! * `2d` Enable simulation only on the first 2 axes `x` and `y`. Incompatible with the feature `3d`, therefore require to disable the default features.
//! * `debug-2d` Render 2d collision shapes
//! * `debug-3d` Render 3d collision shapes
//! * `collision-from-mesh` Add the [`PendingConvexCollision`] component to generate convex hull collision shapes from a mesh
//! * `enhanced-determinism` Enable rapier's [enhanced-determinism](https://rapier.rs/docs/user_guides/rust/determinism)
//!
//!
//! ## Install the plugin
//!
//! The [`PhysicsPlugin`] should be installed to enable physics and collision detection.
//!
//! ```no_run
//! use bevy::prelude::*;
//! use heron::prelude::*;
//!
//! fn main() {
//!   App::new()
//!     .add_plugins(DefaultPlugins)
//!     .add_plugin(PhysicsPlugin::default())
//!     // ... Add your resources and systems
//!     .run();
//! }
//! ```
//!
//! ## Create rigid bodies
//!
//! To create a rigid body, add the [`RigidBody`] to the entity and add a collision shapes with the
//! [`CollisionShape`] component.
//!
//! The position and rotation are defined by the bevy [`GlobalTransform`] component.
//!
//! [`GlobalTransform`]: bevy::prelude::GlobalTransform
//!
//! ```
//! # use bevy::prelude::*;
//! # use heron::prelude::*;
//! fn spawn(mut commands: Commands) {
//! commands
//!
//!     // Spawn any bundle of your choice. Only make sure there is a `GlobalTransform`
//!     .spawn_bundle(SpriteBundle::default())
//!
//!     // Make it a rigid body
//!     .insert(RigidBody::Dynamic)
//!
//!     // Attach a collision shape
//!     .insert(CollisionShape::Sphere { radius: 10.0 })
//!
//!     // Optionally add other useful components...
//!     .insert(Velocity::from_linear(Vec3::X * 2.0))
//!     .insert(Acceleration::from_linear(Vec3::X * 1.0))
//!     .insert(PhysicMaterial { friction: 1.0, density: 10.0, ..Default::default() })
//!     .insert(RotationConstraints::lock());
//! }
//! ```
//!
//! ## Move rigid bodies programmatically
//!
//! When creating games, it is often useful to interact with the physics engine and move bodies
//! programmatically. For this, you have two options: Updating the [`Transform`] or applying a
//! [`Velocity`].
//!
//! [`Transform`]: bevy::prelude::Transform
//!
//! ### Option 1: Update the Transform
//!
//! For positional kinematic bodies ([`RigidBody::KinematicPositionBased`]), if the transform is
//! updated, the body is moved and get an automatically calculated velocity. Physics rules will be
//! applied normally. Updating the transform is a good way to move a kinematic body.
//!
//! For other types of bodies, if the transform is updated, the rigid body will be *teleported* to
//! the new position/rotation, **ignoring physic rules**.
//!
//! ### Option 2: Use the Velocity component
//!
//! For [`RigidBody::Dynamic`] and [`RigidBody::KinematicVelocityBased`] bodies **only**, one can
//! add a [`Velocity`] component to the entity, that will move the body over time. Physics rules
//! will be applied normally.
//!
//! Note that the velocity component is updated by heron to always reflects the current velocity.
//!
//! Defining/updating the velocity is a good way to interact with dynamic bodies.
//!
//! ## See also
//!
//! * How to define a [`RigidBody`]
//! * How to add a [`CollisionShape`]
//! * How to define [`CollisionLayers`]
//! * How to define the world's [`Gravity`]
//! * How to define the world's [`PhysicsTime`]
//! * How to define the [`PhysicMaterial`]
//! * How to get the current [`Collisions`]
//! * How to listen to [`CollisionEvent`]
//! * How to define [`RotationConstraints`]
//! * How to define [`CustomCollisionShape`] for [`heron_rapier`]

use bevy::app::{App, Plugin};

pub use heron_core::*;
pub use heron_macros::*;
use heron_rapier::RapierPlugin;

/// Physics behavior powered by [rapier](https://rapier.rs)
///
/// Allow access to the underlying physics world directly
pub mod rapier_plugin {
    pub use heron_rapier::*;
}

/// Re-exports of the most commons/useful types
pub mod prelude {
    pub use heron_macros::*;

    #[allow(deprecated)]
    pub use crate::{
        stage, Acceleration, AxisAngle, CollisionEvent, CollisionLayers, CollisionShape,
        Collisions, Damping, Gravity, PhysicMaterial, PhysicsLayer, PhysicsPlugin, PhysicsSystem,
        PhysicsTime, RigidBody, RotationConstraints, Velocity,
    };
}

/// Plugin to install to enable collision detection and physics behavior.
#[must_use]
#[derive(Debug, Copy, Clone, Default)]
pub struct PhysicsPlugin {
    #[cfg(debug)]
    debug: heron_debug::DebugPlugin,
}

impl Plugin for PhysicsPlugin {
    fn build(&self, app: &mut App) {
        app.add_plugin(RapierPlugin);

        #[cfg(debug)]
        app.add_plugin(self.debug);
    }
}