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