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