goud_engine/ecs/components/rigidbody/physics_ops.rs
1//! Physics operations, sleep management, and trait impls for [`RigidBody`].
2
3use crate::core::math::Vec2;
4use crate::ecs::Component;
5
6use super::body::RigidBody;
7
8// =============================================================================
9// Physics Operations
10// =============================================================================
11
12impl RigidBody {
13 /// Applies a force to the body (affects acceleration).
14 ///
15 /// Force is accumulated and applied during physics integration.
16 /// Only affects dynamic bodies.
17 ///
18 /// # Arguments
19 ///
20 /// * `_force` - Force vector in Newtons (kg·m/s²)
21 ///
22 /// # Note
23 ///
24 /// This is a placeholder for the public API. Forces will be accumulated
25 /// in a separate `Forces` component or applied directly during physics
26 /// integration in future implementation.
27 pub fn apply_force(&mut self, _force: Vec2) {
28 if !self.is_dynamic() {
29 return;
30 }
31 // Forces will be accumulated in a separate Forces component
32 // or applied directly during integration
33 // This is a placeholder for the public API
34 self.wake();
35 }
36
37 /// Applies an impulse to the body (instant velocity change).
38 ///
39 /// Impulse directly modifies velocity: Δv = impulse / mass
40 /// Only affects dynamic bodies.
41 ///
42 /// # Arguments
43 ///
44 /// * `impulse` - Impulse vector in kg·m/s
45 pub fn apply_impulse(&mut self, impulse: Vec2) {
46 if !self.is_dynamic() {
47 return;
48 }
49 self.linear_velocity = self.linear_velocity + impulse * self.inverse_mass;
50 self.wake();
51 }
52
53 /// Applies an angular impulse to the body.
54 ///
55 /// # Arguments
56 ///
57 /// * `impulse` - Angular impulse in kg·m²/s
58 pub fn apply_angular_impulse(&mut self, impulse: f32) {
59 if !self.is_dynamic() || self.has_fixed_rotation() {
60 return;
61 }
62 self.angular_velocity += impulse * self.inverse_inertia;
63 self.wake();
64 }
65
66 /// Applies damping to velocity (called by physics system).
67 ///
68 /// # Arguments
69 ///
70 /// * `dt` - Delta time in seconds
71 pub fn apply_damping(&mut self, dt: f32) {
72 // Exponential damping: v *= exp(-damping * dt) ≈ v *= (1 - damping * dt)
73 let linear_factor = 1.0 - self.linear_damping * dt;
74 let angular_factor = 1.0 - self.angular_damping * dt;
75
76 self.linear_velocity = self.linear_velocity * linear_factor.max(0.0);
77 self.angular_velocity *= angular_factor.max(0.0);
78 }
79
80 // =========================================================================
81 // Sleep Management
82 // =========================================================================
83
84 /// Puts the body to sleep (optimization).
85 ///
86 /// Sleeping bodies are excluded from physics updates until woken.
87 pub fn sleep(&mut self) {
88 self.set_sleeping(true);
89 self.linear_velocity = Vec2::zero();
90 self.angular_velocity = 0.0;
91 self.reset_sleep_time();
92 }
93
94 /// Wakes the body from sleep.
95 pub fn wake(&mut self) {
96 self.set_sleeping(false);
97 self.reset_sleep_time();
98 }
99
100 /// Updates sleep time based on current motion (called by physics system).
101 ///
102 /// # Arguments
103 ///
104 /// * `dt` - Delta time in seconds
105 /// * `linear_threshold` - Linear velocity threshold for sleep (pixels/s)
106 /// * `angular_threshold` - Angular velocity threshold for sleep (radians/s)
107 ///
108 /// # Returns
109 ///
110 /// True if the body should sleep.
111 pub fn update_sleep_time(
112 &mut self,
113 dt: f32,
114 linear_threshold: f32,
115 angular_threshold: f32,
116 ) -> bool {
117 if !self.can_sleep() || !self.is_dynamic() {
118 self.reset_sleep_time();
119 return false;
120 }
121
122 // Check if motion is below thresholds
123 let below_threshold = self.linear_speed_squared() < linear_threshold * linear_threshold
124 && self.angular_velocity.abs() < angular_threshold;
125
126 if below_threshold {
127 self.increment_sleep_time(dt);
128 true
129 } else {
130 self.reset_sleep_time();
131 false
132 }
133 }
134}
135
136// =============================================================================
137// Trait Implementations
138// =============================================================================
139
140/// ECS component trait implementation.
141impl Component for RigidBody {}
142
143impl std::fmt::Display for RigidBody {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 write!(
146 f,
147 "RigidBody({}, vel: {:?}, mass: {}, sleeping: {})",
148 self.body_type,
149 self.linear_velocity,
150 self.mass,
151 self.is_sleeping()
152 )
153 }
154}