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"
16 #define RIGID_BODIES_MAX_ID_SIZE 36
27 // TODO(#803): the color should not be stored in RigidBodies
36 RigidBodies *create_rigid_bodies(size_t capacity)
43 RigidBodies *rigid_bodies = PUSH_LT(lt, nth_calloc(1, sizeof(RigidBodies)), free);
44 if (rigid_bodies == NULL) {
47 rigid_bodies->lt = lt;
49 rigid_bodies->capacity = capacity;
50 rigid_bodies->count = 0;
52 rigid_bodies->bodies = PUSH_LT(lt, nth_calloc(capacity, sizeof(Rect)), free);
53 if (rigid_bodies->bodies == NULL) {
57 rigid_bodies->velocities = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
58 if (rigid_bodies->velocities == NULL) {
62 rigid_bodies->movements = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
63 if (rigid_bodies->movements == NULL) {
67 rigid_bodies->colors = PUSH_LT(lt, nth_calloc(capacity, sizeof(Color)), free);
68 if (rigid_bodies->colors == NULL) {
72 rigid_bodies->grounded = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
73 if (rigid_bodies->grounded == NULL) {
77 rigid_bodies->forces = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
78 if (rigid_bodies->forces == NULL) {
82 rigid_bodies->deleted = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
83 if (rigid_bodies->deleted == NULL) {
87 rigid_bodies->collided = PUSH_LT(
89 create_hashset(sizeof(size_t) * 2, capacity * 2),
91 if (rigid_bodies->collided == NULL) {
95 rigid_bodies->disabled = PUSH_LT(
97 nth_calloc(capacity, sizeof(bool)),
99 if (rigid_bodies->disabled == NULL) {
106 void destroy_rigid_bodies(RigidBodies *rigid_bodies)
108 trace_assert(rigid_bodies);
109 RETURN_LT0(rigid_bodies->lt);
112 static int rigid_bodies_collide_with_itself(RigidBodies *rigid_bodies)
114 trace_assert(rigid_bodies);
116 if (rigid_bodies->count == 0) {
121 hashset_clear(rigid_bodies->collided);
123 bool the_variable_that_gets_set_when_a_collision_happens_xd = true;
125 for (size_t i = 0; i < 1000 && the_variable_that_gets_set_when_a_collision_happens_xd; ++i) {
126 the_variable_that_gets_set_when_a_collision_happens_xd = false;
127 for (size_t i1 = 0; i1 < rigid_bodies->count - 1; ++i1) {
128 if (rigid_bodies->deleted[i1] || rigid_bodies->disabled[i1]) {
132 for (size_t i2 = i1 + 1; i2 < rigid_bodies->count; ++i2) {
133 if (rigid_bodies->deleted[i2] || rigid_bodies->disabled[i1]) {
137 if (!rects_overlap(rigid_bodies->bodies[i1], rigid_bodies->bodies[i2])) {
141 the_variable_that_gets_set_when_a_collision_happens_xd = true;
145 hashset_insert(rigid_bodies->collided, pair);
147 Vec orient = rect_impulse(&rigid_bodies->bodies[i1], &rigid_bodies->bodies[i2]);
149 if (orient.x > orient.y) {
150 if (rigid_bodies->bodies[i1].y < rigid_bodies->bodies[i2].y) {
151 rigid_bodies->grounded[i1] = true;
153 rigid_bodies->grounded[i2] = true;
157 rigid_bodies->velocities[i1] = vec(rigid_bodies->velocities[i1].x * orient.x, rigid_bodies->velocities[i1].y * orient.y);
158 rigid_bodies->velocities[i2] = vec(rigid_bodies->velocities[i2].x * orient.x, rigid_bodies->velocities[i2].y * orient.y);
159 rigid_bodies->movements[i1] = vec(rigid_bodies->movements[i1].x * orient.x, rigid_bodies->movements[i1].y * orient.y);
160 rigid_bodies->movements[i2] = vec(rigid_bodies->movements[i2].x * orient.x, rigid_bodies->movements[i2].y * orient.y);
166 size_t *collided = hashset_values(rigid_bodies->collided);
167 const size_t n = hashset_count(rigid_bodies->collided);
168 for (size_t i = 0; i < n; ++i) {
169 const size_t i1 = *(collided + i * 2);
170 const size_t i2 = *(collided + i * 2 + 1);
172 rigid_bodies_apply_force(
173 rigid_bodies, i1, vec_sum(rigid_bodies->velocities[i2], rigid_bodies->movements[i2]));
174 rigid_bodies_apply_force(
175 rigid_bodies, i2, vec_sum(rigid_bodies->velocities[i1], rigid_bodies->movements[i1]));
181 static int rigid_bodies_collide_with_platforms(
182 RigidBodies *rigid_bodies,
183 const Platforms *platforms)
185 trace_assert(rigid_bodies);
186 trace_assert(platforms);
188 int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
190 for (size_t i = 0; i < rigid_bodies->count; ++i) {
191 if (rigid_bodies->deleted[i] || rigid_bodies->disabled[i]) {
195 memset(sides, 0, sizeof(int) * RECT_SIDE_N);
197 platforms_touches_rect_sides(platforms, rigid_bodies->bodies[i], sides);
199 if (sides[RECT_SIDE_BOTTOM]) {
200 rigid_bodies->grounded[i] = true;
203 Vec v = platforms_snap_rect(platforms, &rigid_bodies->bodies[i]);
204 rigid_bodies->velocities[i] = vec_entry_mult(rigid_bodies->velocities[i], v);
205 rigid_bodies->movements[i] = vec_entry_mult(rigid_bodies->movements[i], v);
206 rigid_bodies_damper(rigid_bodies, i, vec_entry_mult(v, vec(-16.0f, 0.0f)));
212 int rigid_bodies_collide(RigidBodies *rigid_bodies,
213 const Platforms *platforms)
215 // TODO(#683): RigidBodies should collide only the bodies that were updated on after a previous collision
216 memset(rigid_bodies->grounded, 0, sizeof(bool) * rigid_bodies->count);
218 if (rigid_bodies_collide_with_itself(rigid_bodies) < 0) {
222 if (rigid_bodies_collide_with_platforms(rigid_bodies, platforms) < 0) {
229 int rigid_bodies_update(RigidBodies *rigid_bodies,
233 trace_assert(rigid_bodies);
235 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
239 rigid_bodies->velocities[id] = vec_sum(
240 rigid_bodies->velocities[id],
242 rigid_bodies->forces[id],
245 Vec position = vec(rigid_bodies->bodies[id].x,
246 rigid_bodies->bodies[id].y);
252 rigid_bodies->velocities[id],
253 rigid_bodies->movements[id]),
256 rigid_bodies->bodies[id].x = position.x;
257 rigid_bodies->bodies[id].y = position.y;
259 rigid_bodies->forces[id] = vec(0.0f, 0.0f);
264 int rigid_bodies_render(RigidBodies *rigid_bodies,
268 trace_assert(rigid_bodies);
269 trace_assert(camera);
271 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
275 char text_buffer[256];
277 if (camera_fill_rect(
279 rigid_bodies->bodies[id],
280 rigid_bodies->colors[id]) < 0) {
284 snprintf(text_buffer, 256, "id: %ld", id);
286 if (camera_render_debug_text(
289 vec(rigid_bodies->bodies[id].x,
290 rigid_bodies->bodies[id].y)) < 0) {
294 snprintf(text_buffer, 256, "p:(%.2f, %.2f)",
295 rigid_bodies->bodies[id].x,
296 rigid_bodies->bodies[id].y);
297 if (camera_render_debug_text(
300 vec(rigid_bodies->bodies[id].x,
301 rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 2.0f))) {
305 snprintf(text_buffer, 256, "v:(%.2f, %.2f)",
306 rigid_bodies->velocities[id].x,
307 rigid_bodies->velocities[id].y);
308 if (camera_render_debug_text(
311 vec(rigid_bodies->bodies[id].x,
312 rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 4.0f))) {
316 snprintf(text_buffer, 256, "m:(%.2f, %.2f)",
317 rigid_bodies->movements[id].x,
318 rigid_bodies->movements[id].y);
319 if (camera_render_debug_text(
322 vec(rigid_bodies->bodies[id].x,
323 rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 6.0f))) {
330 RigidBodyId rigid_bodies_add(RigidBodies *rigid_bodies,
334 trace_assert(rigid_bodies);
335 trace_assert(rigid_bodies->count < rigid_bodies->capacity);
337 RigidBodyId id = rigid_bodies->count++;
338 rigid_bodies->bodies[id] = rect;
339 rigid_bodies->colors[id] = color;
344 void rigid_bodies_remove(RigidBodies *rigid_bodies,
347 trace_assert(rigid_bodies);
348 trace_assert(id < rigid_bodies->capacity);
350 rigid_bodies->deleted[id] = true;
353 RigidBodyId rigid_bodies_add_from_line_stream(RigidBodies *rigid_bodies,
354 LineStream *line_stream)
356 trace_assert(rigid_bodies);
357 trace_assert(line_stream);
361 // TODO(#686): id should be part of boxes
362 char id[RIGID_BODIES_MAX_ID_SIZE];
364 if (sscanf(line_stream_next(line_stream),
365 "%" STRINGIFY(RIGID_BODIES_MAX_ID_SIZE) "s%f%f%f%f%6s\n",
370 log_fail("Could not read rigid rect\n");
371 // TODO(#687): rigid_bodies_add_from_line_stream cannot indicate an error properly
375 return rigid_bodies_add(rigid_bodies, rect, hexstr(color));
378 Rect rigid_bodies_hitbox(const RigidBodies *rigid_bodies,
381 trace_assert(rigid_bodies);
382 trace_assert(id < rigid_bodies->count);
384 return rigid_bodies->bodies[id];
387 void rigid_bodies_move(RigidBodies *rigid_bodies,
391 trace_assert(rigid_bodies);
392 trace_assert(id < rigid_bodies->count);
394 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
398 rigid_bodies->movements[id] = movement;
401 int rigid_bodies_touches_ground(const RigidBodies *rigid_bodies,
404 trace_assert(rigid_bodies);
405 trace_assert(id < rigid_bodies->count);
407 return rigid_bodies->grounded[id];
410 void rigid_bodies_apply_omniforce(RigidBodies *rigid_bodies,
413 for (size_t i = 0; i < rigid_bodies->count; ++i) {
414 rigid_bodies_apply_force(rigid_bodies, i, force);
418 void rigid_bodies_apply_force(RigidBodies * rigid_bodies,
422 trace_assert(rigid_bodies);
423 trace_assert(id < rigid_bodies->count);
425 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
429 rigid_bodies->forces[id] = vec_sum(rigid_bodies->forces[id], force);
432 void rigid_bodies_transform_velocity(RigidBodies *rigid_bodies,
436 trace_assert(rigid_bodies);
437 trace_assert(id < rigid_bodies->count);
439 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
443 rigid_bodies->velocities[id] = point_mat3x3_product(
444 rigid_bodies->velocities[id],
448 void rigid_bodies_teleport_to(RigidBodies *rigid_bodies,
452 trace_assert(rigid_bodies);
453 trace_assert(id < rigid_bodies->count);
455 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
459 rigid_bodies->bodies[id].x = position.x;
460 rigid_bodies->bodies[id].y = position.y;
463 void rigid_bodies_damper(RigidBodies *rigid_bodies,
467 trace_assert(rigid_bodies);
468 trace_assert(id < rigid_bodies->count);
470 if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
474 rigid_bodies_apply_force(
477 rigid_bodies->velocities[id].x * v.x,
478 rigid_bodies->velocities[id].y * v.y));
481 void rigid_bodies_disable(RigidBodies *rigid_bodies,
485 trace_assert(rigid_bodies);
486 trace_assert(id < rigid_bodies->count);
488 rigid_bodies->disabled[id] = disabled;