Skip to main content

euv_engine/physics/
struct.rs

1use super::*;
2
3/// Configuration parameters for the physics world simulation.
4#[derive(Clone, Copy, Data, Debug, New, PartialEq, PartialOrd)]
5pub struct PhysicsConfig {
6    /// The gravitational acceleration vector in pixels per second squared.
7    #[get(type(copy))]
8    pub(crate) gravity: Vector2D,
9    /// The linear velocity damping coefficient applied per second.
10    #[get(pub(crate), type(copy))]
11    #[get_mut(pub(crate))]
12    #[set(pub(crate))]
13    pub(crate) linear_damping: f64,
14    /// The angular velocity damping coefficient applied per second.
15    #[get(pub(crate), type(copy))]
16    #[get_mut(pub(crate))]
17    #[set(pub(crate))]
18    pub(crate) angular_damping: f64,
19}
20
21/// A 2D rigid body participating in the physics simulation.
22#[derive(Clone, Data, Debug, New, PartialEq)]
23pub struct RigidBody2D {
24    /// The unique identifier of this body, typically matching a game object ID.
25    #[get(type(copy))]
26    #[get_mut(pub(crate))]
27    pub(crate) id: u64,
28    /// The world-space position of the body's center.
29    #[get(type(copy))]
30    #[get_mut(pub(crate))]
31    pub(crate) position: Vector2D,
32    /// The linear velocity in pixels per second.
33    #[get(type(copy))]
34    #[get_mut(pub(crate))]
35    #[new(skip)]
36    pub(crate) velocity: Vector2D,
37    /// The accumulated force to be applied during the next physics step.
38    #[get(type(copy))]
39    #[get_mut(pub(crate))]
40    #[set(pub(crate))]
41    #[new(skip)]
42    pub(crate) force_accumulator: Vector2D,
43    /// The rotation angle in radians.
44    #[get(type(copy))]
45    #[get_mut(pub(crate))]
46    #[new(skip)]
47    #[get(pub(crate))]
48    #[set(pub(crate))]
49    pub(crate) rotation: f64,
50    /// The angular velocity in radians per second.
51    #[get(type(copy))]
52    #[get_mut(pub(crate))]
53    #[new(skip)]
54    #[set(pub(crate))]
55    pub(crate) angular_velocity: f64,
56    /// The mass of the body in kilograms. Static bodies have a mass of 0.
57    #[get(type(copy))]
58    #[get_mut(pub(crate))]
59    #[set(pub(crate))]
60    pub(crate) mass: f64,
61    /// The precomputed inverse mass (1/mass). Static bodies have 0 inverse mass.
62    #[get(type(copy))]
63    #[get_mut(pub(crate))]
64    #[set(pub(crate))]
65    pub(crate) inverse_mass: f64,
66    /// The restitution (bounciness) coefficient in the range 0.0 to 1.0.
67    #[get(pub(crate), type(copy))]
68    #[get_mut(pub(crate))]
69    #[set(pub(crate))]
70    pub(crate) restitution: f64,
71    /// The friction coefficient for surface contact.
72    #[get(pub(crate), type(copy))]
73    #[get_mut(pub(crate))]
74    pub(crate) friction: f64,
75    /// How this body participates in the simulation.
76    #[get(type(copy))]
77    pub(crate) body_type: BodyType,
78    /// The collider shape attached to this body.
79    #[get(type(copy))]
80    #[new(skip)]
81    #[get(pub(crate))]
82    #[get_mut(pub(crate))]
83    #[set(pub(crate))]
84    pub(crate) collider: Option<BodyCollider>,
85}
86
87/// The physics world managing all rigid bodies and simulation steps.
88#[derive(Clone, Data, Debug, New, PartialEq)]
89pub struct PhysicsWorld2D {
90    /// All rigid bodies in the world.
91    #[get_mut(pub(crate))]
92    #[set(pub(crate))]
93    #[new(skip)]
94    pub(crate) bodies: Vec<RigidBody2D>,
95    /// The simulation configuration.
96    #[get(type(copy))]
97    #[get_mut(pub(crate))]
98    #[set(pub(crate))]
99    pub(crate) config: PhysicsConfig,
100    /// The persistent broad-phase grid, cleared and re-inserted each step so its
101    /// `HashMap` allocation is reused instead of rebuilt per step.
102    #[get_mut(pub(crate))]
103    #[set(pub(crate))]
104    #[new(skip)]
105    pub(crate) grid: SpatialHashGrid2D,
106    /// Scratch buffer reused by grid queries to avoid a per-query `Vec` allocation.
107    #[get_mut(pub(crate))]
108    #[new(skip)]
109    #[get(pub(crate))]
110    #[set(pub(crate))]
111    pub(crate) query_buffer: Vec<usize>,
112    /// Scratch `HashSet` reused by grid queries for candidate dedup.
113    #[get_mut(pub(crate))]
114    #[new(skip)]
115    #[get(pub(crate))]
116    #[set(pub(crate))]
117    pub(crate) query_seen: HashSet<usize>,
118    /// Reusable broad-phase candidate pair list, rebuilt once per step and
119    /// iterated by every solver iteration (the grid is unchanged between them).
120    #[get_mut(pub(crate))]
121    #[set(pub(crate))]
122    #[new(skip)]
123    #[get(pub(crate))]
124    pub(crate) pair_buffer: Vec<(usize, usize)>,
125}
126
127/// Configuration parameters for the 3D physics world simulation.
128#[derive(Clone, Copy, Data, Debug, New, PartialEq, PartialOrd)]
129pub struct PhysicsConfig3D {
130    /// The gravitational acceleration vector in meters per second squared.
131    #[get(pub(crate), type(copy))]
132    #[get_mut(pub(crate))]
133    #[set(pub(crate))]
134    pub(crate) gravity: Vector3D,
135    /// The linear velocity damping coefficient applied per second.
136    #[get(pub(crate), type(copy))]
137    #[get_mut(pub(crate))]
138    #[set(pub(crate))]
139    pub(crate) linear_damping: f64,
140    /// The angular velocity damping coefficient applied per second.
141    #[get(pub(crate), type(copy))]
142    #[get_mut(pub(crate))]
143    #[set(pub(crate))]
144    pub(crate) angular_damping: f64,
145}
146
147/// A 3D rigid body participating in the physics simulation.
148#[derive(Clone, Data, Debug, New, PartialEq)]
149pub struct RigidBody3D {
150    /// The unique identifier of this body, typically matching a game object ID.
151    #[get(type(copy))]
152    #[get_mut(pub(crate))]
153    pub(crate) id: u64,
154    /// The world-space position of the body's center.
155    #[get(type(copy))]
156    #[get_mut(pub(crate))]
157    #[set(pub(crate))]
158    pub(crate) position: Vector3D,
159    /// The linear velocity in meters per second.
160    #[get(type(copy))]
161    #[get_mut(pub(crate))]
162    #[new(skip)]
163    pub(crate) velocity: Vector3D,
164    /// The accumulated force to be applied during the next physics step.
165    #[get(type(copy))]
166    #[get_mut(pub(crate))]
167    #[set(pub(crate))]
168    #[new(skip)]
169    pub(crate) force_accumulator: Vector3D,
170    /// The rotation as a quaternion.
171    #[get(type(copy))]
172    #[get_mut(pub(crate))]
173    #[new(skip)]
174    #[get(pub(crate))]
175    #[set(pub(crate))]
176    pub(crate) rotation: Quaternion,
177    /// The angular velocity as a 3D vector (axis * speed).
178    #[get(type(copy))]
179    #[get_mut(pub(crate))]
180    #[new(skip)]
181    #[set(pub(crate))]
182    pub(crate) angular_velocity: Vector3D,
183    /// The accumulated torque to be applied during the next physics step.
184    #[get(type(copy))]
185    #[get_mut(pub(crate))]
186    #[set(pub(crate))]
187    #[new(skip)]
188    pub(crate) torque_accumulator: Vector3D,
189    /// The mass of the body in kilograms. Static bodies have a mass of 0.
190    #[get(type(copy))]
191    #[get_mut(pub(crate))]
192    #[set(pub(crate))]
193    pub(crate) mass: f64,
194    /// The precomputed inverse mass (1/mass). Static bodies have 0 inverse mass.
195    #[get(type(copy))]
196    #[get_mut(pub(crate))]
197    #[set(pub(crate))]
198    pub(crate) inverse_mass: f64,
199    /// The precomputed inverse moment of inertia (scalar, axis-aligned). Static
200    /// bodies have 0 inverse inertia. Used to convert accumulated torque into
201    /// angular velocity each step.
202    #[get(type(copy))]
203    #[get_mut(pub(crate))]
204    #[set(pub(crate))]
205    #[new(skip)]
206    pub(crate) inverse_inertia: f64,
207    /// The restitution (bounciness) coefficient in the range 0.0 to 1.0.
208    #[get(pub(crate), type(copy))]
209    #[get_mut(pub(crate))]
210    #[set(pub(crate))]
211    pub(crate) restitution: f64,
212    /// The friction coefficient for surface contact.
213    #[get(pub(crate), type(copy))]
214    #[get_mut(pub(crate))]
215    pub(crate) friction: f64,
216    /// How this body participates in the simulation.
217    #[get(type(copy))]
218    pub(crate) body_type: BodyType,
219    /// The 3D collider shape attached to this body.
220    #[get(type(copy))]
221    #[new(skip)]
222    #[get(pub(crate))]
223    #[get_mut(pub(crate))]
224    #[set(pub(crate))]
225    pub(crate) collider: Option<BodyCollider3D>,
226}
227
228/// The 3D physics world managing all rigid bodies and simulation steps.
229#[derive(Clone, Data, Debug, New, PartialEq)]
230pub struct PhysicsWorld3D {
231    /// All rigid bodies in the world.
232    #[get_mut(pub(crate))]
233    #[set(pub(crate))]
234    #[new(skip)]
235    pub(crate) bodies: Vec<RigidBody3D>,
236    /// The simulation configuration.
237    #[get(type(copy))]
238    #[get_mut(pub(crate))]
239    #[set(pub(crate))]
240    pub(crate) config: PhysicsConfig3D,
241    /// The persistent broad-phase grid, cleared and re-inserted each step so its
242    /// `HashMap` allocation is reused instead of rebuilt per step.
243    #[get_mut(pub(crate))]
244    #[set(pub(crate))]
245    #[new(skip)]
246    pub(crate) grid: SpatialHashGrid3D,
247    /// Scratch buffer reused by grid queries to avoid a per-query `Vec` allocation.
248    #[get_mut(pub(crate))]
249    #[new(skip)]
250    #[get(pub(crate))]
251    #[set(pub(crate))]
252    pub(crate) query_buffer: Vec<usize>,
253    /// Scratch `HashSet` reused by grid queries for candidate dedup.
254    #[get_mut(pub(crate))]
255    #[new(skip)]
256    #[get(pub(crate))]
257    #[set(pub(crate))]
258    pub(crate) query_seen: HashSet<usize>,
259    /// Reusable broad-phase candidate pair list, rebuilt once per step and
260    /// iterated by every solver iteration (the grid is unchanged between them).
261    #[get_mut(pub(crate))]
262    #[set(pub(crate))]
263    #[new(skip)]
264    #[get(pub(crate))]
265    pub(crate) pair_buffer: Vec<(usize, usize)>,
266    /// OPT 33: reusable scratch vector for per-body AABB3D snapshots taken
267    /// before draining the spatial grid. The 3D `resolve_collisions` path
268    /// needs to materialise bbox bounds into a Vec to satisfy the
269    /// immutable-then-mutable borrow split; persisting the buffer avoids a
270    /// per-step `Vec::with_capacity(bodies.len())` allocation.
271    #[get_mut(pub(crate))]
272    #[new(skip)]
273    #[get(pub(crate))]
274    #[set(pub(crate))]
275    pub(crate) bbox_buffer: Vec<(usize, AABB3D)>,
276}