]> git.lizzy.rs Git - nothing.git/blob - src/game/level/rigid_bodies.c
bb7382496953b888ae6ab4fd975a5e95ac3ce434
[nothing.git] / src / game / level / rigid_bodies.c
1 #include <stdlib.h>
2 #include <stdbool.h>
3
4 #include "game/camera.h"
5 #include "game/level/platforms.h"
6 #include "system/lt.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"
12 #include "hashset.h"
13
14 #include "./rigid_bodies.h"
15
16 struct RigidBodies
17 {
18     Lt *lt;
19     size_t capacity;
20     size_t count;
21
22     Rect *bodies;
23     Vec *velocities;
24     Vec *movements;
25     bool *grounded;
26     Vec *forces;
27     bool *deleted;
28     bool *disabled;
29 };
30
31 RigidBodies *create_rigid_bodies(size_t capacity)
32 {
33     Lt *lt = create_lt();
34
35     RigidBodies *rigid_bodies = PUSH_LT(lt, nth_calloc(1, sizeof(RigidBodies)), free);
36     if (rigid_bodies == NULL) {
37         RETURN_LT(lt, NULL);
38     }
39     rigid_bodies->lt = lt;
40
41     rigid_bodies->capacity = capacity;
42     rigid_bodies->count = 0;
43
44     rigid_bodies->bodies = PUSH_LT(lt, nth_calloc(capacity, sizeof(Rect)), free);
45     if (rigid_bodies->bodies == NULL) {
46         RETURN_LT(lt, NULL);
47     }
48
49     rigid_bodies->velocities = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
50     if (rigid_bodies->velocities == NULL) {
51         RETURN_LT(lt, NULL);
52     }
53
54     rigid_bodies->movements = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
55     if (rigid_bodies->movements == NULL) {
56         RETURN_LT(lt, NULL);
57     }
58
59     rigid_bodies->grounded = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
60     if (rigid_bodies->grounded == NULL) {
61         RETURN_LT(lt, NULL);
62     }
63
64     rigid_bodies->forces = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
65     if (rigid_bodies->forces == NULL) {
66         RETURN_LT(lt, NULL);
67     }
68
69     rigid_bodies->deleted = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
70     if (rigid_bodies->deleted == NULL) {
71         RETURN_LT(lt, NULL);
72     }
73
74     rigid_bodies->disabled = PUSH_LT(
75         lt,
76         nth_calloc(capacity, sizeof(bool)),
77         free);
78     if (rigid_bodies->disabled == NULL) {
79         RETURN_LT(lt, NULL);
80     }
81
82     return rigid_bodies;
83 }
84
85 void destroy_rigid_bodies(RigidBodies *rigid_bodies)
86 {
87     trace_assert(rigid_bodies);
88     RETURN_LT0(rigid_bodies->lt);
89 }
90
91 int rigid_bodies_collide(RigidBodies *rigid_bodies,
92                          const Platforms *platforms)
93 {
94     // TODO(#683): RigidBodies should collide only the bodies that were updated on after a previous collision
95     memset(rigid_bodies->grounded, 0, sizeof(bool) * rigid_bodies->count);
96
97     if (rigid_bodies->count == 0) {
98         return 0;
99     }
100
101     int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
102
103
104     int t = 100;
105     int the_variable_that_gets_set_when_a_collision_happens_xd = 1;
106     while (t-- > 0 && the_variable_that_gets_set_when_a_collision_happens_xd) {
107         the_variable_that_gets_set_when_a_collision_happens_xd = 0;
108
109         for (size_t i1 = 0; i1 < rigid_bodies->count; ++i1) {
110             if (rigid_bodies->deleted[i1] || rigid_bodies->disabled[i1]) {
111                 continue;
112             }
113
114             // Platforms
115             memset(sides, 0, sizeof(int) * RECT_SIDE_N);
116
117             platforms_touches_rect_sides(platforms, rigid_bodies->bodies[i1], sides);
118
119             for (int i = 0; i < RECT_SIDE_N; ++i) {
120                 if (sides[i]) {
121                     the_variable_that_gets_set_when_a_collision_happens_xd = 1;
122                 }
123             }
124
125             if (sides[RECT_SIDE_BOTTOM]) {
126                 rigid_bodies->grounded[i1] = true;
127             }
128
129             Vec v = platforms_snap_rect(platforms, &rigid_bodies->bodies[i1]);
130             rigid_bodies->velocities[i1] = vec_entry_mult(rigid_bodies->velocities[i1], v);
131             rigid_bodies->movements[i1] = vec_entry_mult(rigid_bodies->movements[i1], v);
132             rigid_bodies_damper(rigid_bodies, i1, vec_entry_mult(v, vec(-16.0f, 0.0f)));
133
134             if (i1 >= rigid_bodies->count - 1) {
135                 continue;
136             }
137
138             // Self-collision
139             for (size_t i2 = i1 + 1; i2 < rigid_bodies->count; ++i2) {
140                 if (rigid_bodies->deleted[i2] || rigid_bodies->disabled[i1]) {
141                     continue;
142                 }
143
144                 if (!rects_overlap(rigid_bodies->bodies[i1], rigid_bodies->bodies[i2])) {
145                     continue;
146                 }
147
148                 the_variable_that_gets_set_when_a_collision_happens_xd = 1;
149
150                 Vec orient = rect_impulse(&rigid_bodies->bodies[i1], &rigid_bodies->bodies[i2]);
151
152                 if (orient.x > orient.y) {
153                     if (rigid_bodies->bodies[i1].y < rigid_bodies->bodies[i2].y) {
154                         rigid_bodies->grounded[i1] = true;
155                     } else {
156                         rigid_bodies->grounded[i2] = true;
157                     }
158                 }
159
160                 rigid_bodies->velocities[i1] = vec(rigid_bodies->velocities[i1].x * orient.x, rigid_bodies->velocities[i1].y * orient.y);
161                 rigid_bodies->velocities[i2] = vec(rigid_bodies->velocities[i2].x * orient.x, rigid_bodies->velocities[i2].y * orient.y);
162                 rigid_bodies->movements[i1] = vec(rigid_bodies->movements[i1].x * orient.x, rigid_bodies->movements[i1].y * orient.y);
163                 rigid_bodies->movements[i2] = vec(rigid_bodies->movements[i2].x * orient.x, rigid_bodies->movements[i2].y * orient.y);
164             }
165         }
166     }
167
168     return 0;
169 }
170
171 int rigid_bodies_update(RigidBodies *rigid_bodies,
172                         RigidBodyId id,
173                         float delta_time)
174 {
175     trace_assert(rigid_bodies);
176
177     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
178         return 0;
179     }
180
181     rigid_bodies->velocities[id] = vec_sum(
182             rigid_bodies->velocities[id],
183             vec_scala_mult(
184                 rigid_bodies->forces[id],
185                 delta_time));
186
187     Vec position = vec(rigid_bodies->bodies[id].x,
188                        rigid_bodies->bodies[id].y);
189
190     position = vec_sum(
191         position,
192         vec_scala_mult(
193             vec_sum(
194                 rigid_bodies->velocities[id],
195                 rigid_bodies->movements[id]),
196             delta_time));
197
198     rigid_bodies->bodies[id].x = position.x;
199     rigid_bodies->bodies[id].y = position.y;
200
201     rigid_bodies->forces[id] = vec(0.0f, 0.0f);
202
203     return 0;
204 }
205
206 int rigid_bodies_render(RigidBodies *rigid_bodies,
207                         RigidBodyId id,
208                         Color color,
209                         Camera *camera)
210 {
211     trace_assert(rigid_bodies);
212     trace_assert(camera);
213
214     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
215         return 0;
216     }
217
218     char text_buffer[256];
219
220     if (camera_fill_rect(
221             camera,
222             rigid_bodies->bodies[id],
223             color) < 0) {
224         return -1;
225     }
226
227     snprintf(text_buffer, 256, "id: %zd", id);
228
229     if (camera_render_debug_text(
230             camera,
231             text_buffer,
232             vec(rigid_bodies->bodies[id].x,
233                 rigid_bodies->bodies[id].y)) < 0) {
234         return -1;
235     }
236
237     snprintf(text_buffer, 256, "p:(%.2f, %.2f)",
238              rigid_bodies->bodies[id].x,
239              rigid_bodies->bodies[id].y);
240     if (camera_render_debug_text(
241             camera,
242             text_buffer,
243             vec(rigid_bodies->bodies[id].x,
244                 rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 2.0f))) {
245         return -1;
246     }
247
248     snprintf(text_buffer, 256, "v:(%.2f, %.2f)",
249              rigid_bodies->velocities[id].x,
250              rigid_bodies->velocities[id].y);
251     if (camera_render_debug_text(
252             camera,
253             text_buffer,
254             vec(rigid_bodies->bodies[id].x,
255                 rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 4.0f))) {
256         return -1;
257     }
258
259     snprintf(text_buffer, 256, "m:(%.2f, %.2f)",
260              rigid_bodies->movements[id].x,
261              rigid_bodies->movements[id].y);
262     if (camera_render_debug_text(
263             camera,
264             text_buffer,
265             vec(rigid_bodies->bodies[id].x,
266                 rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 6.0f))) {
267         return -1;
268     }
269
270     return 0;
271 }
272
273 RigidBodyId rigid_bodies_add(RigidBodies *rigid_bodies,
274                              Rect rect)
275 {
276     trace_assert(rigid_bodies);
277     trace_assert(rigid_bodies->count < rigid_bodies->capacity);
278
279     RigidBodyId id = rigid_bodies->count++;
280     rigid_bodies->bodies[id] = rect;
281
282     return id;
283 }
284
285 void rigid_bodies_remove(RigidBodies *rigid_bodies,
286                          RigidBodyId id)
287 {
288     trace_assert(rigid_bodies);
289     trace_assert(id < rigid_bodies->capacity);
290
291     rigid_bodies->deleted[id] = true;
292 }
293
294 Rect rigid_bodies_hitbox(const RigidBodies *rigid_bodies,
295                          RigidBodyId id)
296 {
297     trace_assert(rigid_bodies);
298     trace_assert(id < rigid_bodies->count);
299
300     return rigid_bodies->bodies[id];
301 }
302
303 void rigid_bodies_move(RigidBodies *rigid_bodies,
304                        RigidBodyId id,
305                        Vec movement)
306 {
307     trace_assert(rigid_bodies);
308     trace_assert(id < rigid_bodies->count);
309
310     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
311         return;
312     }
313
314     rigid_bodies->movements[id] = movement;
315 }
316
317 int rigid_bodies_touches_ground(const RigidBodies *rigid_bodies,
318                                 RigidBodyId id)
319 {
320     trace_assert(rigid_bodies);
321     trace_assert(id < rigid_bodies->count);
322
323     return rigid_bodies->grounded[id];
324 }
325
326 void rigid_bodies_apply_omniforce(RigidBodies *rigid_bodies,
327                                   Vec force)
328 {
329     for (size_t i = 0; i < rigid_bodies->count; ++i) {
330         rigid_bodies_apply_force(rigid_bodies, i, force);
331     }
332 }
333
334 void rigid_bodies_apply_force(RigidBodies * rigid_bodies,
335                               RigidBodyId id,
336                               Vec force)
337 {
338     trace_assert(rigid_bodies);
339     trace_assert(id < rigid_bodies->count);
340
341     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
342         return;
343     }
344
345     rigid_bodies->forces[id] = vec_sum(rigid_bodies->forces[id], force);
346 }
347
348 void rigid_bodies_transform_velocity(RigidBodies *rigid_bodies,
349                                      RigidBodyId id,
350                                      mat3x3 trans_mat)
351 {
352     trace_assert(rigid_bodies);
353     trace_assert(id < rigid_bodies->count);
354
355     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
356         return;
357     }
358
359     rigid_bodies->velocities[id] = point_mat3x3_product(
360         rigid_bodies->velocities[id],
361         trans_mat);
362 }
363
364 void rigid_bodies_teleport_to(RigidBodies *rigid_bodies,
365                               RigidBodyId id,
366                               Vec position)
367 {
368     trace_assert(rigid_bodies);
369     trace_assert(id < rigid_bodies->count);
370
371     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
372         return;
373     }
374
375     rigid_bodies->bodies[id].x = position.x;
376     rigid_bodies->bodies[id].y = position.y;
377 }
378
379 void rigid_bodies_damper(RigidBodies *rigid_bodies,
380                          RigidBodyId id,
381                          Vec v)
382 {
383     trace_assert(rigid_bodies);
384     trace_assert(id < rigid_bodies->count);
385
386     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
387         return;
388     }
389
390     rigid_bodies_apply_force(
391         rigid_bodies, id,
392         vec(
393             rigid_bodies->velocities[id].x * v.x,
394             rigid_bodies->velocities[id].y * v.y));
395 }
396
397 void rigid_bodies_disable(RigidBodies *rigid_bodies,
398                           RigidBodyId id,
399                           bool disabled)
400 {
401     trace_assert(rigid_bodies);
402     trace_assert(id < rigid_bodies->count);
403
404     rigid_bodies->disabled[id] = disabled;
405 }