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