heron_core/
velocity.rs

1use std::ops::{Mul, MulAssign};
2
3use bevy::ecs::component::Component;
4use bevy::math::prelude::*;
5use bevy::reflect::prelude::*;
6use duplicate::duplicate_item;
7
8use crate::utils::NearZero;
9
10/// Component that defines the linear and angular velocity.
11///
12/// It must be inserted on the same entity of a [`RigidBody`](crate::RigidBody)
13///
14/// This component can be used for controlling and reading the velocity of the rigid body.
15///
16/// # Example
17///
18/// ```
19/// # use bevy::prelude::*;
20/// # use heron_core::*;
21/// # use std::f32::consts::PI;
22///
23/// fn spawn(mut commands: Commands) {
24///     commands.spawn_bundle(todo!("Spawn your sprite/mesh, incl. at least a GlobalTransform"))
25///         .insert(CollisionShape::Sphere { radius: 1.0 })
26///         .insert(
27///             Velocity::from_linear(Vec3::X * 10.0)
28///                 .with_angular(AxisAngle::new(Vec3::Z, 0.5 * PI))
29///         );
30/// }
31/// ```
32#[derive(Debug, Component, Copy, Clone, PartialEq, Default, Reflect)]
33pub struct Velocity {
34    /// Linear velocity in units-per-second on each axis
35    ///
36    /// The unit is your game unit, be it meter, pixel or anything else
37    pub linear: Vec3,
38
39    /// Angular velocity in radians-per-second around an axis
40    pub angular: AxisAngle,
41}
42
43/// Component that defines the linear and angular acceleration.
44///
45/// It must be inserted on the same entity of a [`RigidBody`](crate::RigidBody)
46///
47/// The linear part is in "unit" per second squared on each axis, represented as a `Vec3`. (The unit, being your game unit, be it pixel or anything else)
48/// The angular part is in radians per second squared around an axis, represented as an [`AxisAngle`]
49///
50/// # Example
51///
52/// ```
53/// # use bevy::prelude::*;
54/// # use heron_core::*;
55/// # use std::f32::consts::PI;
56///
57/// fn spawn(mut commands: Commands) {
58///     commands.spawn_bundle(todo!("Spawn your sprite/mesh, incl. at least a GlobalTransform"))
59///         .insert(CollisionShape::Sphere { radius: 1.0 })
60///         .insert(
61///             Acceleration::from_linear(Vec3::X * 1.0)
62///                 .with_angular(AxisAngle::new(Vec3::Z, 0.05 * PI))
63///         );
64/// }
65/// ```
66#[derive(Debug, Component, Copy, Clone, PartialEq, Default, Reflect)]
67pub struct Acceleration {
68    /// Linear acceleration in units-per-second-squared on each axis
69    pub linear: Vec3,
70
71    /// Angular acceleration in radians-per-second-squared around an axis
72    pub angular: AxisAngle,
73}
74
75/// Component that defines the linear and angular damping.
76///
77/// It must be inserted on the same entity of a [`RigidBody`](crate::RigidBody)
78///
79/// The higher the values, the stronger slow-downs.
80/// Default values are 0.0 (no damping at all).
81///
82/// # Example
83///
84/// ```
85/// # use bevy::prelude::*;
86/// # use heron_core::*;
87///
88/// fn spawn(mut commands: Commands) {
89///     commands.spawn_bundle(todo!("Spawn your sprite/mesh, incl. at least a GlobalTransform"))
90///         .insert(CollisionShape::Sphere { radius: 1.0 })
91///         .insert(
92///             Damping::from_linear(0.5)
93///                 .with_angular(0.2)
94///         );
95/// }
96/// ```
97#[derive(Debug, Copy, Clone, PartialEq, Default, Reflect, Component)]
98pub struct Damping {
99    /// Linear damping coefficient
100    pub linear: f32,
101
102    /// Angular damping coefficient
103    pub angular: f32,
104}
105
106/// An [axis-angle] representation
107///
108/// [axis-angle]: https://en.wikipedia.org/wiki/Axis%E2%80%93angle_representation
109#[derive(Debug, Copy, Clone, PartialEq, Default, Reflect)]
110pub struct AxisAngle(Vec3);
111
112impl Velocity {
113    /// Returns a linear velocity from a vector
114    #[must_use]
115    pub fn from_linear(linear: Vec3) -> Self {
116        Self {
117            linear,
118            angular: AxisAngle::default(),
119        }
120    }
121
122    /// Returns an angular velocity from a vector
123    #[must_use]
124    pub fn from_angular(angular: AxisAngle) -> Self {
125        Self {
126            angular,
127            linear: Vec3::ZERO,
128        }
129    }
130
131    /// Returns a new version with the given linear velocity
132    #[must_use]
133    pub fn with_linear(mut self, linear: Vec3) -> Self {
134        self.linear = linear;
135        self
136    }
137
138    /// Returns a new version with the given angular velocity
139    #[must_use]
140    pub fn with_angular(mut self, angular: AxisAngle) -> Self {
141        self.angular = angular;
142        self
143    }
144}
145
146impl Acceleration {
147    /// Returns a linear acceleration from a vector
148    #[must_use]
149    pub fn from_linear(linear: Vec3) -> Self {
150        Self {
151            linear,
152            angular: AxisAngle::default(),
153        }
154    }
155
156    /// Returns an angular acceleration from a vector
157    #[must_use]
158    pub fn from_angular(angular: AxisAngle) -> Self {
159        Self {
160            angular,
161            linear: Vec3::ZERO,
162        }
163    }
164
165    /// Returns a new version with the given linear acceleration
166    #[must_use]
167    pub fn with_linear(mut self, linear: Vec3) -> Self {
168        self.linear = linear;
169        self
170    }
171
172    /// Returns a new version with the given angular acceleration
173    #[must_use]
174    pub fn with_angular(mut self, angular: AxisAngle) -> Self {
175        self.angular = angular;
176        self
177    }
178}
179
180impl Damping {
181    /// Returns a linear damping
182    #[must_use]
183    pub fn from_linear(linear: f32) -> Self {
184        Self {
185            linear,
186            angular: 0.0,
187        }
188    }
189
190    /// Returns an angular damping
191    #[must_use]
192    pub fn from_angular(angular: f32) -> Self {
193        Self {
194            angular,
195            linear: 0.0,
196        }
197    }
198
199    /// Returns a new version with the given linear damping
200    #[must_use]
201    pub fn with_linear(mut self, linear: f32) -> Self {
202        self.linear = linear;
203        self
204    }
205
206    /// Returns a new version with the given angular damping
207    #[must_use]
208    pub fn with_angular(mut self, angular: f32) -> Self {
209        self.angular = angular;
210        self
211    }
212}
213
214#[duplicate_item(
215  Velocity;
216  [ Velocity ];
217  [ Acceleration ];
218)]
219impl From<Vec2> for Velocity {
220    fn from(v: Vec2) -> Self {
221        Self::from_linear(v.extend(0.0))
222    }
223}
224
225#[duplicate_item(
226  Velocity;
227  [ Velocity ];
228  [ Acceleration ];
229)]
230impl From<Vec3> for Velocity {
231    fn from(linear: Vec3) -> Self {
232        Self::from_linear(linear)
233    }
234}
235
236#[duplicate_item(
237  Velocity;
238  [ Velocity ];
239  [ Acceleration ];
240)]
241impl From<Velocity> for Vec3 {
242    fn from(Velocity { linear, .. }: Velocity) -> Self {
243        linear
244    }
245}
246
247#[duplicate_item(
248  Velocity;
249  [ Velocity ];
250  [ Acceleration ];
251)]
252impl From<AxisAngle> for Velocity {
253    fn from(angular: AxisAngle) -> Self {
254        Self::from_angular(angular)
255    }
256}
257
258#[duplicate_item(
259  Velocity;
260  [ Velocity ];
261  [ Acceleration ];
262)]
263impl From<Quat> for Velocity {
264    fn from(quat: Quat) -> Self {
265        Self::from_angular(quat.into())
266    }
267}
268
269#[duplicate_item(
270  Velocity;
271  [ Velocity ];
272  [ Acceleration ];
273)]
274impl From<Velocity> for AxisAngle {
275    fn from(Velocity { angular, .. }: Velocity) -> Self {
276        angular
277    }
278}
279
280#[duplicate_item(
281  Velocity;
282  [ Velocity ];
283  [ Acceleration ];
284)]
285impl From<Velocity> for Quat {
286    fn from(Velocity { angular, .. }: Velocity) -> Self {
287        angular.into()
288    }
289}
290
291impl From<Vec3> for AxisAngle {
292    fn from(v: Vec3) -> Self {
293        Self(v)
294    }
295}
296
297impl From<AxisAngle> for Vec3 {
298    fn from(AxisAngle(v): AxisAngle) -> Self {
299        v
300    }
301}
302
303impl From<AxisAngle> for f32 {
304    fn from(AxisAngle(v): AxisAngle) -> Self {
305        v.length()
306    }
307}
308
309#[duplicate_item(
310  Velocity;
311  [ Velocity ];
312  [ Acceleration ];
313)]
314impl NearZero for Velocity {
315    fn is_near_zero(self) -> bool {
316        self.linear.is_near_zero() && self.angular.is_near_zero()
317    }
318}
319
320impl MulAssign<f32> for AxisAngle {
321    fn mul_assign(&mut self, rhs: f32) {
322        self.0 = self.0 * rhs;
323    }
324}
325
326impl Mul<f32> for AxisAngle {
327    type Output = Self;
328
329    fn mul(mut self, rhs: f32) -> Self::Output {
330        self *= rhs;
331        self
332    }
333}
334
335impl Mul<AxisAngle> for f32 {
336    type Output = AxisAngle;
337
338    fn mul(self, mut rhs: AxisAngle) -> Self::Output {
339        rhs *= self;
340        rhs
341    }
342}
343
344impl AxisAngle {
345    /// Create a new axis-angle
346    #[inline]
347    #[must_use]
348    pub fn new(axis: Vec3, angle: f32) -> Self {
349        Self(axis.normalize() * angle)
350    }
351
352    /// Squared angle.
353    ///
354    /// In general faster than `angle` because it doesn't need to perform a square-root
355    #[inline]
356    #[must_use]
357    pub fn angle_squared(self) -> f32 {
358        self.0.length_squared()
359    }
360
361    /// Angle around the axis.
362    ///
363    /// For comparison you may consider `angle_squared`, that doesn't need to perform a square root.
364    #[inline]
365    #[must_use]
366    pub fn angle(self) -> f32 {
367        self.0.length()
368    }
369
370    /// Returns the axis **NOT** normalized.
371    #[inline]
372    #[must_use]
373    pub fn axis(self) -> Vec3 {
374        self.0
375    }
376}
377
378impl NearZero for AxisAngle {
379    fn is_near_zero(self) -> bool {
380        self.0.is_near_zero()
381    }
382}
383
384impl From<Quat> for AxisAngle {
385    fn from(quat: Quat) -> Self {
386        let length = quat.length();
387        let (axis, angle) = quat.to_axis_angle();
388        Self(axis.normalize() * (angle * length))
389    }
390}
391
392impl From<AxisAngle> for Quat {
393    fn from(axis_angle: AxisAngle) -> Self {
394        if axis_angle.is_near_zero() {
395            Quat::IDENTITY
396        } else {
397            let angle = axis_angle.0.length();
398            Quat::from_axis_angle(axis_angle.0 / angle, angle)
399        }
400    }
401}