4 #include "game/camera.h"
5 #include "game/level/platforms.h"
7 #include "system/nth_alloc.h"
8 #include "system/stacktrace.h"
9 #include "system/line_stream.h"
10 #include "system/str.h"
11 #include "system/log.h"
14 #include "./rigid_bodies.h"
32 RigidBodies *create_rigid_bodies(size_t capacity)
39 RigidBodies *rigid_bodies = PUSH_LT(lt, nth_calloc(1, sizeof(RigidBodies)), free);
40 if (rigid_bodies == NULL) {
43 rigid_bodies->lt = lt;
45 rigid_bodies->capacity = capacity;
46 rigid_bodies->count = 0;
48 rigid_bodies->bodies = PUSH_LT(lt, nth_calloc(capacity, sizeof(Rect)), free);
49 if (rigid_bodies->bodies == NULL) {
53 rigid_bodies->velocities = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
54 if (rigid_bodies->velocities == NULL) {
58 rigid_bodies->movements = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
59 if (rigid_bodies->movements == NULL) {
63 rigid_bodies->grounded = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
64 if (rigid_bodies->grounded == NULL) {
68 rigid_bodies->forces = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
69 if (rigid_bodies->forces == NULL) {
73 rigid_bodies->deleted = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
74 if (rigid_bodies->deleted == NULL) {
78 rigid_bodies->collided = PUSH_LT(
80 create_hashset(sizeof(size_t) * 2, capacity * 2),
82 if (rigid_bodies->collided == NULL) {
86 rigid_bodies->disabled = PUSH_LT(
88 nth_calloc(capacity, sizeof(bool)),
90 if (rigid_bodies->disabled == NULL) {
97 void destroy_rigid_bodies(RigidBodies *rigid_bodies)
99 trace_assert(rigid_bodies);
100 RETURN_LT0(rigid_bodies->lt);
103 static int rigid_bodies_collide_with_itself(RigidBodies *rigid_bodies)
105 trace_assert(rigid_bodies);
107 if (rigid_bodies->count == 0) {
112 hashset_clear(rigid_bodies->collided);
114 bool the_variable_that_gets_set_when_a_collision_happens_xd = true;
116 for (size_t i = 0; i < 1000 && the_variable_that_gets_set_when_a_collision_happens_xd; ++i) {
117 the_variable_that_gets_set_when_a_collision_happens_xd = false;
118 for (size_t i1 = 0; i1 < rigid_bodies->count - 1; ++i1) {
119 if (rigid_bodies->deleted[i1] || rigid_bodies->disabled[i1]) {
123 for (size_t i2 = i1 + 1; i2 < rigid_bodies->count; ++i2) {
124 if (rigid_bodies->deleted[i2] || rigid_bodies->disabled[i1]) {
128 if (!rects_overlap(rigid_bodies->bodies[i1], rigid_bodies->bodies[i2])) {
132 the_variable_that_gets_set_when_a_collision_happens_xd = true;
136 hashset_insert(rigid_bodies->collided, pair);
138 Vec orient = rect_impulse(&rigid_bodies->bodies[i1], &rigid_bodies->bodies[i2]);
140 if (orient.x > orient.y) {
141 if (rigid_bodies->bodies[i1].y < rigid_bodies->bodies[i2].y) {
142 rigid_bodies->grounded[i1] = true;
144 rigid_bodies->grounded[i2] = true;
148 rigid_bodies->velocities[i1] = vec(rigid_bodies->velocities[i1].x * orient.x, rigid_bodies->velocities[i1].y * orient.y);
149 rigid_bodies->velocities[i2] = vec(rigid_bodies->velocities[i2].x * orient.x, rigid_bodies->velocities[i2].y * orient.y);
150 rigid_bodies->movements[i1] = vec(rigid_bodies->movements[i1].x * orient.x, rigid_bodies->movements[i1].y * orient.y);
151 rigid_bodies->movements[i2] = vec(rigid_bodies->movements[i2].x * orient.x, rigid_bodies->movements[i2].y * orient.y);
157 size_t *collided = hashset_values(rigid_bodies->collided);
158 const size_t n = hashset_count(rigid_bodies->collided);
159 for (size_t i = 0; i < n; ++i) {
160 const size_t i1 = *(collided + i * 2);
161 const size_t i2 = *(collided + i * 2 + 1);
163 rigid_bodies_apply_force(
164 rigid_bodies, i1, vec_sum(rigid_bodies->velocities[i2], rigid_bodies->movements[i2]));
165 rigid_bodies_apply_force(
166 rigid_bodies, i2, vec_sum(rigid_bodies->velocities[i1], rigid_bodies->movements[i1]));
172 static int rigid_bodies_collide_with_platforms(
173 RigidBodies *rigid_bodies,
174 const Platforms *platforms)
176 trace_assert(rigid_bodies);
177 trace_assert(platforms);
179 int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
181 for (size_t i = 0; i < rigid_bodies->count; ++i) {
182 if (rigid_bodies->deleted[i] || rigid_bodies->disabled[i]) {
186 memset(sides, 0, sizeof(int) * RECT_SIDE_N);
188 platforms_touches_rect_sides(platforms, rigid_bodies->bodies[i], sides);
190 if (sides[RECT_SIDE_BOTTOM]) {
191 rigid_bodies->grounded[i] = true;
194 Vec v = platforms_snap_rect(platforms, &rigid_bodies->bodies[i]);
195 rigid_bodies->velocities[i] = vec_entry_mult(rigid_bodies->velocities[i], v);
196 rigid_bodies->movements[i] = vec_entry_mult(rigid_bodies->movements[i], v);
197 rigid_bodies_damper(rigid_bodies, i, vec_entry_mult(v, vec(-16.0f, 0.0f)));
203 int rigid_bodies_collide(RigidBodies *rigid_bodies,
204 const Platforms *platforms)
206 // TODO(#683): RigidBodies should collide only the bodies that were updated on after a previous collision
207 memset(rigid_bodies->grounded, 0, sizeof(bool) * rigid_bodies->count);
209 if (rigid_bodies_collide_with_itself(rigid_bodies) < 0) {
213 if (rigid_bodies_collide_with_platforms(rigid_bodies, platforms) < 0) {
220 int rigid_bodies_update(RigidBodies *rigid_bodies,
224 trace_assert(rigid_bodies);
226 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
230 rigid_bodies->velocities[id] = vec_sum(
231 rigid_bodies->velocities[id],
233 rigid_bodies->forces[id],
236 Vec position = vec(rigid_bodies->bodies[id].x,
237 rigid_bodies->bodies[id].y);
243 rigid_bodies->velocities[id],
244 rigid_bodies->movements[id]),
247 rigid_bodies->bodies[id].x = position.x;
248 rigid_bodies->bodies[id].y = position.y;
250 rigid_bodies->forces[id] = vec(0.0f, 0.0f);
255 int rigid_bodies_render(RigidBodies *rigid_bodies,
260 trace_assert(rigid_bodies);
261 trace_assert(camera);
263 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
267 char text_buffer[256];
269 if (camera_fill_rect(
271 rigid_bodies->bodies[id],
276 snprintf(text_buffer, 256, "id: %ld", id);
278 if (camera_render_debug_text(
281 vec(rigid_bodies->bodies[id].x,
282 rigid_bodies->bodies[id].y)) < 0) {
286 snprintf(text_buffer, 256, "p:(%.2f, %.2f)",
287 rigid_bodies->bodies[id].x,
288 rigid_bodies->bodies[id].y);
289 if (camera_render_debug_text(
292 vec(rigid_bodies->bodies[id].x,
293 rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 2.0f))) {
297 snprintf(text_buffer, 256, "v:(%.2f, %.2f)",
298 rigid_bodies->velocities[id].x,
299 rigid_bodies->velocities[id].y);
300 if (camera_render_debug_text(
303 vec(rigid_bodies->bodies[id].x,
304 rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 4.0f))) {
308 snprintf(text_buffer, 256, "m:(%.2f, %.2f)",
309 rigid_bodies->movements[id].x,
310 rigid_bodies->movements[id].y);
311 if (camera_render_debug_text(
314 vec(rigid_bodies->bodies[id].x,
315 rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 6.0f))) {
322 RigidBodyId rigid_bodies_add(RigidBodies *rigid_bodies,
325 trace_assert(rigid_bodies);
326 trace_assert(rigid_bodies->count < rigid_bodies->capacity);
328 RigidBodyId id = rigid_bodies->count++;
329 rigid_bodies->bodies[id] = rect;
334 void rigid_bodies_remove(RigidBodies *rigid_bodies,
337 trace_assert(rigid_bodies);
338 trace_assert(id < rigid_bodies->capacity);
340 rigid_bodies->deleted[id] = true;
343 Rect rigid_bodies_hitbox(const RigidBodies *rigid_bodies,
346 trace_assert(rigid_bodies);
347 trace_assert(id < rigid_bodies->count);
349 return rigid_bodies->bodies[id];
352 void rigid_bodies_move(RigidBodies *rigid_bodies,
356 trace_assert(rigid_bodies);
357 trace_assert(id < rigid_bodies->count);
359 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
363 rigid_bodies->movements[id] = movement;
366 int rigid_bodies_touches_ground(const RigidBodies *rigid_bodies,
369 trace_assert(rigid_bodies);
370 trace_assert(id < rigid_bodies->count);
372 return rigid_bodies->grounded[id];
375 void rigid_bodies_apply_omniforce(RigidBodies *rigid_bodies,
378 for (size_t i = 0; i < rigid_bodies->count; ++i) {
379 rigid_bodies_apply_force(rigid_bodies, i, force);
383 void rigid_bodies_apply_force(RigidBodies * rigid_bodies,
387 trace_assert(rigid_bodies);
388 trace_assert(id < rigid_bodies->count);
390 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
394 rigid_bodies->forces[id] = vec_sum(rigid_bodies->forces[id], force);
397 void rigid_bodies_transform_velocity(RigidBodies *rigid_bodies,
401 trace_assert(rigid_bodies);
402 trace_assert(id < rigid_bodies->count);
404 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
408 rigid_bodies->velocities[id] = point_mat3x3_product(
409 rigid_bodies->velocities[id],
413 void rigid_bodies_teleport_to(RigidBodies *rigid_bodies,
417 trace_assert(rigid_bodies);
418 trace_assert(id < rigid_bodies->count);
420 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
424 rigid_bodies->bodies[id].x = position.x;
425 rigid_bodies->bodies[id].y = position.y;
428 void rigid_bodies_damper(RigidBodies *rigid_bodies,
432 trace_assert(rigid_bodies);
433 trace_assert(id < rigid_bodies->count);
435 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
439 rigid_bodies_apply_force(
442 rigid_bodies->velocities[id].x * v.x,
443 rigid_bodies->velocities[id].y * v.y));
446 void rigid_bodies_disable(RigidBodies *rigid_bodies,
450 trace_assert(rigid_bodies);
451 trace_assert(id < rigid_bodies->count);
453 rigid_bodies->disabled[id] = disabled;