avian2d/dynamics/rigid_body/
world_query.rs

1#![allow(missing_docs)]
2
3use crate::prelude::*;
4use bevy::{
5    ecs::query::QueryData,
6    prelude::{Entity, Has, Ref},
7};
8
9/// A `WorldQuery` to make querying and modifying rigid bodies more convenient.
10#[derive(QueryData)]
11#[query_data(mutable)]
12pub struct RigidBodyQuery {
13    pub entity: Entity,
14    pub rb: Ref<'static, RigidBody>,
15    pub position: &'static mut Position,
16    pub rotation: &'static mut Rotation,
17    pub linear_velocity: &'static mut LinearVelocity,
18    pub angular_velocity: &'static mut AngularVelocity,
19    pub mass: &'static mut ComputedMass,
20    pub angular_inertia: &'static mut ComputedAngularInertia,
21    pub center_of_mass: &'static mut ComputedCenterOfMass,
22    pub friction: Option<&'static Friction>,
23    pub restitution: Option<&'static Restitution>,
24    pub locked_axes: Option<&'static LockedAxes>,
25    pub dominance: Option<&'static Dominance>,
26    pub is_sleeping: Has<Sleeping>,
27    pub is_sensor: Has<Sensor>,
28}
29
30impl RigidBodyQueryItem<'_, '_> {
31    /// Computes the velocity at the given `point` relative to the center of the body.
32    pub fn velocity_at_point(&self, point: Vector) -> Vector {
33        #[cfg(feature = "2d")]
34        {
35            self.linear_velocity.0 + self.angular_velocity.0 * point.perp()
36        }
37        #[cfg(feature = "3d")]
38        {
39            self.linear_velocity.0 + self.angular_velocity.cross(point)
40        }
41    }
42
43    /// Computes the effective inverse mass, taking into account any translation locking.
44    pub fn effective_inverse_mass(&self) -> Vector {
45        if !self.rb.is_dynamic() {
46            return Vector::ZERO;
47        }
48
49        let mut inv_mass = Vector::splat(self.mass.inverse());
50
51        if let Some(locked_axes) = self.locked_axes {
52            inv_mass = locked_axes.apply_to_vec(inv_mass);
53        }
54
55        inv_mass
56    }
57
58    /// Returns the local angular inertia. If the rigid body is not dynamic, the returned angular inertia is infinite.
59    pub fn angular_inertia(&self) -> ComputedAngularInertia {
60        if self.rb.is_dynamic() {
61            *self.angular_inertia
62        } else {
63            ComputedAngularInertia::INFINITY
64        }
65    }
66
67    /// Computes the effective world-space angular inertia, taking into account any rotation locking.
68    pub fn effective_global_angular_inertia(&self) -> ComputedAngularInertia {
69        if !self.rb.is_dynamic() {
70            return ComputedAngularInertia::INFINITY;
71        }
72
73        #[cfg(feature = "2d")]
74        let mut angular_inertia = *self.angular_inertia;
75        #[cfg(feature = "3d")]
76        let mut angular_inertia = self.angular_inertia.rotated(self.rotation.0);
77
78        if let Some(locked_axes) = self.locked_axes {
79            angular_inertia = locked_axes.apply_to_angular_inertia(angular_inertia);
80        }
81
82        angular_inertia
83    }
84
85    /// Returns the [dominance](Dominance) of the body.
86    ///
87    /// If it isn't specified, the default of `0` is returned for dynamic bodies.
88    /// For static and kinematic bodies, `i8::MAX + 1` (`128`) is always returned instead.
89    pub fn dominance(&self) -> i16 {
90        if !self.rb.is_dynamic() {
91            i8::MAX as i16 + 1
92        } else {
93            self.dominance.map_or(0, |dominance| dominance.0) as i16
94        }
95    }
96}
97
98impl RigidBodyQueryReadOnlyItem<'_, '_> {
99    /// Computes the velocity at the given `point` relative to the center of mass.
100    pub fn velocity_at_point(&self, point: Vector) -> Vector {
101        #[cfg(feature = "2d")]
102        {
103            self.linear_velocity.0 + self.angular_velocity.0 * point.perp()
104        }
105        #[cfg(feature = "3d")]
106        {
107            self.linear_velocity.0 + self.angular_velocity.cross(point)
108        }
109    }
110
111    /// Returns the mass. If the rigid body is not dynamic, the returned mass is infinite.
112    pub fn mass(&self) -> ComputedMass {
113        if self.rb.is_dynamic() {
114            *self.mass
115        } else {
116            ComputedMass::INFINITY
117        }
118    }
119
120    /// Computes the effective inverse mass, taking into account any translation locking.
121    pub fn effective_inverse_mass(&self) -> Vector {
122        if !self.rb.is_dynamic() {
123            return Vector::ZERO;
124        }
125
126        let mut inv_mass = Vector::splat(self.mass.inverse());
127
128        if let Some(locked_axes) = self.locked_axes {
129            inv_mass = locked_axes.apply_to_vec(inv_mass);
130        }
131
132        inv_mass
133    }
134
135    /// Returns the local angular inertia. If the rigid body is not dynamic, the returned angular inertia is infinite.
136    pub fn angular_inertia(&self) -> ComputedAngularInertia {
137        if self.rb.is_dynamic() {
138            *self.angular_inertia
139        } else {
140            ComputedAngularInertia::INFINITY
141        }
142    }
143
144    /// Computes the effective world-space angular inertia, taking into account any rotation locking.
145    pub fn effective_global_angular_inertia(&self) -> ComputedAngularInertia {
146        if !self.rb.is_dynamic() {
147            return ComputedAngularInertia::INFINITY;
148        }
149
150        #[cfg(feature = "2d")]
151        let mut angular_inertia = *self.angular_inertia;
152        #[cfg(feature = "3d")]
153        let mut angular_inertia = self.angular_inertia.rotated(self.rotation.0);
154
155        if let Some(locked_axes) = self.locked_axes {
156            angular_inertia = locked_axes.apply_to_angular_inertia(angular_inertia);
157        }
158
159        angular_inertia
160    }
161
162    /// Returns the [dominance](Dominance) of the body.
163    ///
164    /// If it isn't specified, the default of `0` is returned for dynamic bodies.
165    /// For static and kinematic bodies, `i8::MAX + 1` (`128`) is always returned instead.
166    pub fn dominance(&self) -> i16 {
167        if !self.rb.is_dynamic() {
168            i8::MAX as i16 + 1
169        } else {
170            self.dominance.map_or(0, |dominance| dominance.0) as i16
171        }
172    }
173}