]> git.lizzy.rs Git - nothing.git/blob - src/game/level/rigid_bodies.c
667916e87fc7b5cf9e31688f1454b001e0fe6555
[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     Vec2f *velocities;
24     Vec2f *movements;
25     bool *grounded;
26     Vec2f *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(Vec2f)), 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(Vec2f)), 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(Vec2f)), 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     memset(rigid_bodies->grounded, 0, sizeof(bool) * rigid_bodies->count);
95
96     if (rigid_bodies->count == 0) {
97         return 0;
98     }
99
100     int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
101
102
103     int t = 100;
104     int the_variable_that_gets_set_when_a_collision_happens_xd = 1;
105     while (t-- > 0 && the_variable_that_gets_set_when_a_collision_happens_xd) {
106         the_variable_that_gets_set_when_a_collision_happens_xd = 0;
107
108         for (size_t i1 = 0; i1 < rigid_bodies->count; ++i1) {
109             if (rigid_bodies->deleted[i1] || rigid_bodies->disabled[i1]) {
110                 continue;
111             }
112
113             // Platforms
114             memset(sides, 0, sizeof(int) * RECT_SIDE_N);
115
116             platforms_touches_rect_sides(platforms, rigid_bodies->bodies[i1], sides);
117
118             for (int i = 0; i < RECT_SIDE_N; ++i) {
119                 if (sides[i]) {
120                     the_variable_that_gets_set_when_a_collision_happens_xd = 1;
121                 }
122             }
123
124             if (sides[RECT_SIDE_BOTTOM]) {
125                 rigid_bodies->grounded[i1] = true;
126             }
127
128             Vec2f v = platforms_snap_rect(platforms, &rigid_bodies->bodies[i1]);
129             rigid_bodies->velocities[i1] = vec_entry_mult(rigid_bodies->velocities[i1], v);
130             rigid_bodies->movements[i1] = vec_entry_mult(rigid_bodies->movements[i1], v);
131             rigid_bodies_damper(rigid_bodies, i1, vec_entry_mult(v, vec(-16.0f, 0.0f)));
132
133             if (i1 >= rigid_bodies->count - 1) {
134                 continue;
135             }
136
137             // Self-collision
138             for (size_t i2 = i1 + 1; i2 < rigid_bodies->count; ++i2) {
139                 if (rigid_bodies->deleted[i2] || rigid_bodies->disabled[i1]) {
140                     continue;
141                 }
142
143                 if (!rects_overlap(rigid_bodies->bodies[i1], rigid_bodies->bodies[i2])) {
144                     continue;
145                 }
146
147                 the_variable_that_gets_set_when_a_collision_happens_xd = 1;
148
149                 Vec2f orient = rect_impulse(&rigid_bodies->bodies[i1], &rigid_bodies->bodies[i2]);
150
151                 if (orient.x > orient.y) {
152                     if (rigid_bodies->bodies[i1].y < rigid_bodies->bodies[i2].y) {
153                         rigid_bodies->grounded[i1] = true;
154                     } else {
155                         rigid_bodies->grounded[i2] = true;
156                     }
157                 }
158
159                 rigid_bodies->velocities[i1] = vec(rigid_bodies->velocities[i1].x * orient.x, rigid_bodies->velocities[i1].y * orient.y);
160                 rigid_bodies->velocities[i2] = vec(rigid_bodies->velocities[i2].x * orient.x, rigid_bodies->velocities[i2].y * orient.y);
161                 rigid_bodies->movements[i1] = vec(rigid_bodies->movements[i1].x * orient.x, rigid_bodies->movements[i1].y * orient.y);
162                 rigid_bodies->movements[i2] = vec(rigid_bodies->movements[i2].x * orient.x, rigid_bodies->movements[i2].y * orient.y);
163             }
164         }
165     }
166
167     return 0;
168 }
169
170 int rigid_bodies_update(RigidBodies *rigid_bodies,
171                         RigidBodyId id,
172                         float delta_time)
173 {
174     trace_assert(rigid_bodies);
175
176     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
177         return 0;
178     }
179
180     rigid_bodies->velocities[id] = vec_sum(
181             rigid_bodies->velocities[id],
182             vec_scala_mult(
183                 rigid_bodies->forces[id],
184                 delta_time));
185
186     Vec2f position = vec(rigid_bodies->bodies[id].x,
187                        rigid_bodies->bodies[id].y);
188
189     position = vec_sum(
190         position,
191         vec_scala_mult(
192             vec_sum(
193                 rigid_bodies->velocities[id],
194                 rigid_bodies->movements[id]),
195             delta_time));
196
197     rigid_bodies->bodies[id].x = position.x;
198     rigid_bodies->bodies[id].y = position.y;
199
200     rigid_bodies->forces[id] = vec(0.0f, 0.0f);
201
202     return 0;
203 }
204
205 int rigid_bodies_render(RigidBodies *rigid_bodies,
206                         RigidBodyId id,
207                         Color color,
208                         const Camera *camera)
209 {
210     trace_assert(rigid_bodies);
211     trace_assert(camera);
212
213     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
214         return 0;
215     }
216
217     char text_buffer[256];
218
219     if (camera_fill_rect(
220             camera,
221             rigid_bodies->bodies[id],
222             color) < 0) {
223         return -1;
224     }
225
226     snprintf(text_buffer, 256, "id: %zd", id);
227
228     if (camera_render_debug_text(
229             camera,
230             text_buffer,
231             vec(rigid_bodies->bodies[id].x,
232                 rigid_bodies->bodies[id].y)) < 0) {
233         return -1;
234     }
235
236     snprintf(text_buffer, 256, "p:(%.2f, %.2f)",
237              rigid_bodies->bodies[id].x,
238              rigid_bodies->bodies[id].y);
239     if (camera_render_debug_text(
240             camera,
241             text_buffer,
242             vec(rigid_bodies->bodies[id].x,
243                 rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 2.0f))) {
244         return -1;
245     }
246
247     snprintf(text_buffer, 256, "v:(%.2f, %.2f)",
248              rigid_bodies->velocities[id].x,
249              rigid_bodies->velocities[id].y);
250     if (camera_render_debug_text(
251             camera,
252             text_buffer,
253             vec(rigid_bodies->bodies[id].x,
254                 rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 4.0f))) {
255         return -1;
256     }
257
258     snprintf(text_buffer, 256, "m:(%.2f, %.2f)",
259              rigid_bodies->movements[id].x,
260              rigid_bodies->movements[id].y);
261     if (camera_render_debug_text(
262             camera,
263             text_buffer,
264             vec(rigid_bodies->bodies[id].x,
265                 rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 6.0f))) {
266         return -1;
267     }
268
269     return 0;
270 }
271
272 RigidBodyId rigid_bodies_add(RigidBodies *rigid_bodies,
273                              Rect rect)
274 {
275     trace_assert(rigid_bodies);
276     trace_assert(rigid_bodies->count < rigid_bodies->capacity);
277
278     RigidBodyId id = rigid_bodies->count++;
279     rigid_bodies->bodies[id] = rect;
280
281     return id;
282 }
283
284 void rigid_bodies_remove(RigidBodies *rigid_bodies,
285                          RigidBodyId id)
286 {
287     trace_assert(rigid_bodies);
288     trace_assert(id < rigid_bodies->capacity);
289
290     rigid_bodies->deleted[id] = true;
291 }
292
293 Rect rigid_bodies_hitbox(const RigidBodies *rigid_bodies,
294                          RigidBodyId id)
295 {
296     trace_assert(rigid_bodies);
297     trace_assert(id < rigid_bodies->count);
298
299     return rigid_bodies->bodies[id];
300 }
301
302 void rigid_bodies_move(RigidBodies *rigid_bodies,
303                        RigidBodyId id,
304                        Vec2f movement)
305 {
306     trace_assert(rigid_bodies);
307     trace_assert(id < rigid_bodies->count);
308
309     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
310         return;
311     }
312
313     rigid_bodies->movements[id] = movement;
314 }
315
316 int rigid_bodies_touches_ground(const RigidBodies *rigid_bodies,
317                                 RigidBodyId id)
318 {
319     trace_assert(rigid_bodies);
320     trace_assert(id < rigid_bodies->count);
321
322     return rigid_bodies->grounded[id];
323 }
324
325 void rigid_bodies_apply_omniforce(RigidBodies *rigid_bodies,
326                                   Vec2f force)
327 {
328     for (size_t i = 0; i < rigid_bodies->count; ++i) {
329         rigid_bodies_apply_force(rigid_bodies, i, force);
330     }
331 }
332
333 void rigid_bodies_apply_force(RigidBodies * rigid_bodies,
334                               RigidBodyId id,
335                               Vec2f force)
336 {
337     trace_assert(rigid_bodies);
338     trace_assert(id < rigid_bodies->count);
339
340     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
341         return;
342     }
343
344     rigid_bodies->forces[id] = vec_sum(rigid_bodies->forces[id], force);
345 }
346
347 void rigid_bodies_transform_velocity(RigidBodies *rigid_bodies,
348                                      RigidBodyId id,
349                                      mat3x3 trans_mat)
350 {
351     trace_assert(rigid_bodies);
352     trace_assert(id < rigid_bodies->count);
353
354     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
355         return;
356     }
357
358     rigid_bodies->velocities[id] = point_mat3x3_product(
359         rigid_bodies->velocities[id],
360         trans_mat);
361 }
362
363 void rigid_bodies_teleport_to(RigidBodies *rigid_bodies,
364                               RigidBodyId id,
365                               Vec2f position)
366 {
367     trace_assert(rigid_bodies);
368     trace_assert(id < rigid_bodies->count);
369
370     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
371         return;
372     }
373
374     rigid_bodies->bodies[id].x = position.x;
375     rigid_bodies->bodies[id].y = position.y;
376 }
377
378 void rigid_bodies_damper(RigidBodies *rigid_bodies,
379                          RigidBodyId id,
380                          Vec2f v)
381 {
382     trace_assert(rigid_bodies);
383     trace_assert(id < rigid_bodies->count);
384
385     if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
386         return;
387     }
388
389     rigid_bodies_apply_force(
390         rigid_bodies, id,
391         vec(
392             rigid_bodies->velocities[id].x * v.x,
393             rigid_bodies->velocities[id].y * v.y));
394 }
395
396 void rigid_bodies_disable(RigidBodies *rigid_bodies,
397                           RigidBodyId id,
398                           bool disabled)
399 {
400     trace_assert(rigid_bodies);
401     trace_assert(id < rigid_bodies->count);
402
403     rigid_bodies->disabled[id] = disabled;
404 }