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