bevy_tnua/util/
command_impl_helpers.rs1use bevy::prelude::*;
2
3use bevy_tnua_physics_integration_layer::data_for_backends::TnuaVelChange;
4use bevy_tnua_physics_integration_layer::math::{AdjustPrecision, Float, Quaternion, Vector3};
5
6use crate::TnuaBasisContext;
7use crate::basis_action_traits::{TnuaActionContext, TnuaBasis};
8
9pub trait MotionHelper {
14 fn frame_duration(&self) -> Float;
15 fn up_direction(&self) -> Dir3;
16 fn gravity(&self) -> Vector3;
17 fn position(&self) -> Vector3;
18 fn velocity(&self) -> Vector3;
19 fn rotation(&self) -> Quaternion;
20 fn angvel(&self) -> Vector3;
21
22 fn negate_gravity(&self) -> TnuaVelChange {
24 TnuaVelChange::acceleration(-self.gravity())
25 }
26
27 fn adjust_velocity(
31 &self,
32 target: Vector3,
33 acceleration: Float,
34 dimlim: impl Fn(Vector3) -> Vector3,
35 ) -> TnuaVelChange {
36 let delta = dimlim(target - self.velocity());
37 let allowed_this_frame = acceleration * self.frame_duration();
38 if delta.length_squared() <= allowed_this_frame.powi(2) {
39 TnuaVelChange::boost(delta)
40 } else {
41 TnuaVelChange::acceleration(delta.normalize_or_zero() * acceleration)
42 }
43 }
44
45 fn adjust_vertical_velocity(&self, target: Float, acceleration: Float) -> TnuaVelChange {
47 let up_vector = self.up_direction().adjust_precision();
48 self.adjust_velocity(up_vector * target, acceleration, |v| {
49 v.project_onto_normalized(up_vector)
50 })
51 }
52
53 fn adjust_horizontal_velocity(&self, target: Vector3, acceleration: Float) -> TnuaVelChange {
55 self.adjust_velocity(target, acceleration, |v| {
56 v.reject_from_normalized(self.up_direction().adjust_precision())
57 })
58 }
59
60 fn turn_to_direction(&self, desired_forward: Dir3, up_direction: Dir3) -> TnuaVelChange {
63 let up_vector = up_direction.adjust_precision();
64 let current_forward = self.rotation().mul_vec3(Vector3::NEG_Z);
65 let rotation_along_up_axis = crate::util::rotation_arc_around_axis(
66 up_direction,
67 current_forward,
68 desired_forward.adjust_precision(),
69 )
70 .unwrap_or(0.0);
71 let desired_angvel = rotation_along_up_axis / self.frame_duration();
72 let existing_angvel = self.angvel().dot(up_vector);
73 let torque_to_turn = desired_angvel - existing_angvel;
74 TnuaVelChange::boost(torque_to_turn * up_vector)
75 }
76
77 fn hard_stop(
92 &self,
93 direction: Dir3,
94 stop_at: Vector3,
95 current_vel_change: &TnuaVelChange,
96 ) -> TnuaVelChange {
97 let expected_velocity =
98 self.velocity() + current_vel_change.calc_mean_boost(self.frame_duration());
99 let expected_velocity_in_direction = expected_velocity.dot(direction.adjust_precision());
100 if expected_velocity_in_direction <= 0.0 {
101 return TnuaVelChange::default();
102 }
103 let distance_in_direction = (stop_at - self.position()).dot(direction.adjust_precision());
104 let max_allowed_velocity = distance_in_direction / self.frame_duration();
105 let velocity_to_cut = expected_velocity_in_direction - max_allowed_velocity;
106 if 0.0 < velocity_to_cut {
107 TnuaVelChange::boost(velocity_to_cut * -direction.adjust_precision())
108 } else {
109 TnuaVelChange::default()
110 }
111 }
112}
113
114impl MotionHelper for TnuaBasisContext<'_> {
115 fn frame_duration(&self) -> Float {
116 self.frame_duration
117 }
118
119 fn up_direction(&self) -> Dir3 {
120 self.up_direction
121 }
122
123 fn gravity(&self) -> Vector3 {
124 self.tracker.gravity
125 }
126
127 fn position(&self) -> Vector3 {
128 self.tracker.translation
129 }
130
131 fn velocity(&self) -> Vector3 {
132 self.tracker.velocity
133 }
134
135 fn rotation(&self) -> Quaternion {
136 self.tracker.rotation
137 }
138
139 fn angvel(&self) -> Vector3 {
140 self.tracker.angvel
141 }
142}
143
144impl<B: TnuaBasis> MotionHelper for TnuaActionContext<'_, B> {
145 fn frame_duration(&self) -> Float {
146 self.frame_duration
147 }
148
149 fn up_direction(&self) -> Dir3 {
150 self.up_direction
151 }
152
153 fn gravity(&self) -> Vector3 {
154 self.tracker.gravity
155 }
156
157 fn position(&self) -> Vector3 {
158 self.tracker.translation
159 }
160
161 fn velocity(&self) -> Vector3 {
162 self.tracker.velocity
163 }
164
165 fn rotation(&self) -> Quaternion {
166 self.tracker.rotation
167 }
168
169 fn angvel(&self) -> Vector3 {
170 self.tracker.angvel
171 }
172}