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