1use rg3d_core::{
2 math::vec3::Vec3,
3 visitor::{Visit, VisitResult, Visitor},
4 pool::Handle
5};
6use crate::{
7 contact::Contact,
8 convex_shape::{ConvexShape, TriangleShape},
9 gjk_epa,
10 static_geometry::{
11 StaticTriangle,
12 StaticGeometry
13 }
14};
15
16bitflags! {
17 pub struct CollisionFlags: u8 {
18 const NONE = 0;
19 const DISABLE_COLLISION_RESPONSE = 1;
21 }
22}
23
24#[derive(Debug)]
25pub struct RigidBody {
26 pub(in crate) position: Vec3,
27 pub(in crate) shape: ConvexShape,
28 pub(in crate) last_position: Vec3,
29 pub(in crate) acceleration: Vec3,
30 pub(in crate) contacts: Vec<Contact>,
31 pub(in crate) friction: Vec3,
32 pub(in crate) gravity: Vec3,
33 pub(in crate) speed_limit: f32,
34 pub(in crate) lifetime: Option<f32>,
35 pub user_flags: u64,
36 pub collision_group: u64,
37 pub collision_mask: u64,
38 pub collision_flags: CollisionFlags,
39}
40
41impl Default for RigidBody {
42 fn default() -> Self {
43 Self::new(ConvexShape::Dummy)
44 }
45}
46
47impl Visit for RigidBody {
48 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
49 visitor.enter_region(name)?;
50
51 let mut id = self.shape.id();
52 id.visit("ShapeKind", visitor)?;
53 if visitor.is_reading() {
54 self.shape = ConvexShape::new(id)?;
55 }
56 self.shape.visit("Shape", visitor)?;
57
58 self.position.visit("Position", visitor)?;
59 self.last_position.visit("LastPosition", visitor)?;
60 self.acceleration.visit("Acceleration", visitor)?;
61 self.contacts.visit("Contacts", visitor)?;
62 self.friction.visit("Friction", visitor)?;
63 self.gravity.visit("Gravity", visitor)?;
64 self.speed_limit.visit("SpeedLimit", visitor)?;
65 self.user_flags.visit("UserFlags", visitor)?;
66 self.collision_group.visit("CollisionGroup", visitor)?;
67 self.collision_mask.visit("CollisionMask", visitor)?;
68
69 let mut collision_flags = self.collision_flags.bits;
70 collision_flags.visit("CollisionFlags", visitor)?;
71 if visitor.is_reading() {
72 self.collision_flags = CollisionFlags::from_bits(collision_flags).unwrap();
73 }
74
75 visitor.leave_region()
76 }
77}
78
79impl Clone for RigidBody {
80 fn clone(&self) -> Self {
81 Self {
82 position: self.position,
83 last_position: self.last_position,
84 acceleration: self.acceleration,
85 contacts: Vec::new(),
86 friction: self.friction,
87 gravity: self.gravity,
88 shape: self.shape.clone(),
89 speed_limit: self.speed_limit,
90 lifetime: self.lifetime,
91 user_flags: self.user_flags,
92 collision_group: self.collision_group,
93 collision_mask: self.collision_mask,
94 collision_flags: CollisionFlags::NONE
95 }
96 }
97}
98
99impl RigidBody {
100 pub fn new(shape: ConvexShape) -> Self {
101 Self {
102 position: Vec3::ZERO,
103 last_position: Vec3::ZERO,
104 acceleration: Vec3::ZERO,
105 friction: Vec3::new(0.2, 0.2, 0.2),
106 gravity: Vec3::new(0.0, -9.81, 0.0),
107 shape,
108 contacts: Vec::new(),
109 speed_limit: 0.75,
110 lifetime: None,
111 user_flags: 0,
112 collision_group: 1,
113 collision_mask: std::u64::MAX,
114 collision_flags: CollisionFlags::NONE
115 }
116 }
117
118 #[inline]
119 pub fn get_position(&self) -> Vec3 {
120 self.position
121 }
122
123 #[inline]
124 pub fn set_position(&mut self, p: Vec3) -> &mut Self {
125 self.position = p;
126 self.last_position = p;
127 self
128 }
129
130 #[inline]
131 pub fn move_by(&mut self, v: Vec3) -> &mut Self {
132 self.position += v;
133 self
134 }
135
136 pub fn offset_by(&mut self, v: Vec3) -> &mut Self {
137 self.position += v;
138 self.last_position = self.position;
139 self
140 }
141
142 #[inline]
143 pub fn set_shape(&mut self, shape: ConvexShape) -> &mut Self {
144 self.shape = shape;
145 self
146 }
147
148 #[inline]
149 pub fn get_shape(&self) -> &ConvexShape {
150 &self.shape
151 }
152
153 #[inline]
154 pub fn get_shape_mut(&mut self) -> &mut ConvexShape {
155 &mut self.shape
156 }
157
158 #[inline]
159 pub fn set_friction(&mut self, friction: Vec3) -> &mut Self {
160 self.friction.x = friction.x.max(0.0).min(1.0);
161 self.friction.y = friction.y.max(0.0).min(1.0);
162 self.friction.z = friction.z.max(0.0).min(1.0);
163 self
164 }
165
166 #[inline]
167 pub fn get_friction(&self) -> Vec3 {
168 self.friction
169 }
170
171 #[inline]
172 pub fn set_x_velocity(&mut self, x: f32) -> &mut Self {
173 self.last_position.x = self.position.x - x;
174 self
175 }
176
177 #[inline]
178 pub fn set_y_velocity(&mut self, y: f32) -> &mut Self {
179 self.last_position.y = self.position.y - y;
180 self
181 }
182
183 #[inline]
184 pub fn set_z_velocity(&mut self, z: f32) -> &mut Self {
185 self.last_position.z = self.position.z - z;
186 self
187 }
188
189 #[inline]
190 pub fn set_velocity(&mut self, v: Vec3) -> &mut Self {
191 self.last_position = self.position - v;
192 self
193 }
194
195 #[inline]
196 pub fn get_velocity(&self) -> Vec3 {
197 self.position - self.last_position
198 }
199
200 #[inline]
201 pub fn get_contacts(&self) -> &[Contact] {
202 self.contacts.as_slice()
203 }
204
205 #[inline]
206 pub fn set_gravity(&mut self, gravity: Vec3) -> &mut Self {
207 self.gravity = gravity;
208 self
209 }
210
211 #[inline]
212 pub fn get_gravity(&self) -> Vec3 {
213 self.gravity
214 }
215
216 #[inline]
217 pub fn set_lifetime(&mut self, time_seconds: f32) -> &mut Self {
218 self.lifetime = Some(time_seconds);
219 self
220 }
221
222 #[inline]
223 pub fn get_lifetime(&self) -> Option<f32> {
224 self.lifetime
225 }
226
227 pub fn verlet(&mut self, sqr_delta_time: f32, air_friction: f32) {
228 let friction =
229 if !self.collision_flags.contains(CollisionFlags::DISABLE_COLLISION_RESPONSE) && !self.contacts.is_empty() {
230 self.friction
231 } else {
232 Vec3::new(air_friction, air_friction, air_friction)
233 };
234
235 let last_position = self.position;
236
237 self.position = Vec3 {
239 x: (2.0 - friction.x) * self.position.x - (1.0 - friction.x) * self.last_position.x + self.acceleration.x * sqr_delta_time,
240 y: (2.0 - friction.y) * self.position.y - (1.0 - friction.y) * self.last_position.y + self.acceleration.y * sqr_delta_time,
241 z: (2.0 - friction.z) * self.position.z - (1.0 - friction.z) * self.last_position.z + self.acceleration.z * sqr_delta_time,
242 };
243
244 self.last_position = last_position;
245
246 self.acceleration = Vec3::ZERO;
247
248 let velocity = self.last_position - self.position;
249 let sqr_speed = velocity.sqr_len();
250 if sqr_speed > self.speed_limit * self.speed_limit {
251 if let Some(direction) = velocity.normalized() {
252 self.last_position = self.position - direction.scale(self.speed_limit);
253 }
254 }
255 }
256
257 pub fn solve_triangle_collision(&mut self, triangle: &StaticTriangle, triangle_index: usize, static_geom: Handle<StaticGeometry>) {
258 let triangle_shape = ConvexShape::Triangle(TriangleShape {
259 vertices: triangle.points
260 });
261
262 if let Some(simplex) = gjk_epa::gjk_is_intersects(&self.shape, self.position, &triangle_shape, Vec3::ZERO) {
263 if let Some(penetration_info) = gjk_epa::epa_get_penetration_info(simplex, &self.shape, self.position, &triangle_shape, Vec3::ZERO) {
264 self.position -= penetration_info.penetration_vector;
265
266 self.contacts.push(Contact {
267 static_geom,
268 body: Handle::NONE,
269 position: penetration_info.contact_point,
270 normal: (-penetration_info.penetration_vector).normalized().unwrap_or(Vec3::ZERO),
271 triangle_index: triangle_index as u32,
272 })
273 }
274 }
275 }
276
277 pub fn solve_rigid_body_collision(&mut self, self_handle: Handle<RigidBody>, other: &mut Self, other_handle: Handle<RigidBody>) {
278 if let Some(simplex) = gjk_epa::gjk_is_intersects(&self.shape, self.position, &other.shape, other.position) {
279 if let Some(penetration_info) = gjk_epa::epa_get_penetration_info(simplex, &self.shape, self.position, &other.shape, other.position) {
280 let half_push = penetration_info.penetration_vector.scale(0.5);
281 let response_disabled =
282 self.collision_flags.contains(CollisionFlags::DISABLE_COLLISION_RESPONSE) ||
283 other.collision_flags.contains(CollisionFlags::DISABLE_COLLISION_RESPONSE);
284
285 if !response_disabled {
286 self.position -= half_push;
287 }
288 self.contacts.push(Contact {
289 body: other_handle,
290 position: penetration_info.contact_point,
291 normal: (-penetration_info.penetration_vector).normalized().unwrap_or(Vec3::UP),
293 triangle_index: 0,
294 static_geom: Default::default()
295 });
296 if !response_disabled {
297 other.position += half_push;
298 }
299 other.contacts.push(Contact {
300 body: self_handle,
301 position: penetration_info.contact_point,
302 normal: (penetration_info.penetration_vector).normalized().unwrap_or(Vec3::UP),
304 triangle_index: 0,
305 static_geom: Default::default()
306 })
307 }
308 }
309 }
310}