4 #include "game/camera.h"
5 #include "game/level/platforms.h"
7 #include "system/nth_alloc.h"
8 #include "system/stacktrace.h"
10 #include "./rigid_bodies.h"
29 static const Vec opposing_rect_side_forces[RECT_SIDE_N] = {
30 { .x = 1.0f, .y = 0.0f }, /* RECT_SIDE_LEFT = 0, */
31 { .x = -1.0f, .y = 0.0f }, /* RECT_SIDE_RIGHT, */
32 { .x = 0.0f, .y = 1.0f, }, /* RECT_SIDE_TOP, */
33 { .x = 0.0f, .y = -1.0f, } /* RECT_SIDE_BOTTOM, */
36 static Vec opposing_force_by_sides(int sides[RECT_SIDE_N])
38 Vec opposing_force = {
43 for (Rect_side side = 0; side < RECT_SIDE_N; ++side) {
47 opposing_rect_side_forces[side]);
51 return opposing_force;
54 RigidBodies *create_rigid_bodies(size_t capacity)
61 RigidBodies *rigid_bodies = PUSH_LT(lt, nth_calloc(1, sizeof(RigidBodies)), free);
62 if (rigid_bodies == NULL) {
65 rigid_bodies->lt = lt;
67 rigid_bodies->capacity = capacity;
68 rigid_bodies->count = 0;
70 rigid_bodies->id = PUSH_LT(
72 nth_calloc(ID_SIZE, sizeof(char)),
74 if (rigid_bodies->id == NULL) {
78 rigid_bodies->bodies = PUSH_LT(lt, nth_calloc(capacity, sizeof(Rect)), free);
79 if (rigid_bodies->bodies == NULL) {
83 rigid_bodies->velocities = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
84 if (rigid_bodies->velocities == NULL) {
88 rigid_bodies->movements = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
89 if (rigid_bodies->movements == NULL) {
93 rigid_bodies->colors = PUSH_LT(lt, nth_calloc(capacity, sizeof(Color)), free);
94 if (rigid_bodies->colors == NULL) {
98 rigid_bodies->grounded = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
99 if (rigid_bodies->grounded == NULL) {
103 rigid_bodies->forces = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
104 if (rigid_bodies->forces == NULL) {
111 void destroy_rigid_bodies(RigidBodies *rigid_bodies)
113 trace_assert(rigid_bodies);
114 RETURN_LT0(rigid_bodies->lt);
117 static int rigid_bodies_collide_with_itself(RigidBodies *rigid_bodies)
119 trace_assert(rigid_bodies);
121 if (rigid_bodies->count == 0) {
125 for (size_t i1 = 0; i1 < rigid_bodies->count - 1; ++i1) {
126 for (size_t i2 = i1 + 1; i2 < rigid_bodies->count; ++i2) {
127 // TODO(#653): Rigid Bodies perform too many conversions between rect and two vecs representation
128 // Maybe it's just better to represent the bodies as rects all the time?
129 // TODO(#654): Rigid Bodies don't exchange forces with each other
130 if (!rects_overlap(rigid_bodies->bodies[i1], rigid_bodies->bodies[i2])) {
134 rect_impulse(&rigid_bodies->bodies[i1], &rigid_bodies->bodies[i2]);
141 static int rigid_bodies_collide_with_platforms(
142 RigidBodies *rigid_bodies,
143 const Platforms *platforms)
145 trace_assert(rigid_bodies);
146 trace_assert(platforms);
148 int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
150 for (size_t i = 0; i < rigid_bodies->count; ++i) {
151 memset(sides, 0, sizeof(int) * RECT_SIDE_N);
153 platforms_touches_rect_sides(platforms, rigid_bodies->bodies[i], sides);
155 if (sides[RECT_SIDE_BOTTOM]) {
156 rigid_bodies->grounded[i] = true;
159 /* TODO(#655): Opposing force notion in Rigid Bodies seems redundant */
160 Vec opforce_direction = opposing_force_by_sides(sides);
162 if (fabs(opforce_direction.x) > 1e-6 && (opforce_direction.x < 0.0f) != ((rigid_bodies->velocities[i].x + rigid_bodies->movements[i].x) < 0.0f)) {
163 rigid_bodies->velocities[i].x = 0.0f;
164 rigid_bodies->movements[i].x = 0.0f;
167 if (fabs(opforce_direction.y) > 1e-6 && (opforce_direction.y < 0.0f) != ((rigid_bodies->velocities[i].y + rigid_bodies->movements[i].y) < 0.0f)) {
168 rigid_bodies->velocities[i].y = 0.0f;
169 rigid_bodies->movements[i].y = 0.0f;
171 if (vec_length(rigid_bodies->velocities[i]) > 1e-6) {
172 rigid_bodies_apply_force(
175 vec_neg(rigid_bodies->velocities[i]),
180 rigid_bodies->bodies[i] = platforms_snap_rect(platforms, rigid_bodies->bodies[i]);
186 int rigid_bodies_collide(RigidBodies *rigid_bodies,
187 const Platforms *platforms)
189 if (rigid_bodies_collide_with_itself(rigid_bodies) < 0) {
193 if (rigid_bodies_collide_with_platforms(rigid_bodies, platforms) < 0) {
200 int rigid_bodies_update(RigidBodies *rigid_bodies,
203 trace_assert(rigid_bodies);
205 memset(rigid_bodies->grounded, 0,
206 sizeof(bool) * rigid_bodies->count);
208 for (size_t i = 0; i < rigid_bodies->count; ++i) {
209 rigid_bodies->velocities[i] = vec_sum(
210 rigid_bodies->velocities[i],
212 rigid_bodies->forces[i],
216 for (size_t i = 0; i < rigid_bodies->count; ++i) {
217 Vec position = vec(rigid_bodies->bodies[i].x,
218 rigid_bodies->bodies[i].y);
224 rigid_bodies->velocities[i],
225 rigid_bodies->movements[i]),
228 rigid_bodies->bodies[i].x = position.x;
229 rigid_bodies->bodies[i].y = position.y;
232 memset(rigid_bodies->forces, 0,
233 sizeof(Vec) * rigid_bodies->count);
238 int rigid_bodies_render(RigidBodies *rigid_bodies,
241 trace_assert(rigid_bodies);
242 trace_assert(camera);
244 for (size_t i = 0; i < rigid_bodies->count; ++i) {
245 if (camera_fill_rect(
247 rigid_bodies->bodies[i],
248 rigid_bodies->colors[i]) < 0) {
252 snprintf(rigid_bodies->id, ID_SIZE, "%ld", i);
254 if (camera_render_debug_text(
257 vec(rigid_bodies->bodies[i].x,
258 rigid_bodies->bodies[i].y)) < 0) {
266 RigidBodyId rigid_bodies_add(RigidBodies *rigid_bodies,
270 trace_assert(rigid_bodies);
271 trace_assert(rigid_bodies->count < rigid_bodies->capacity);
273 RigidBodyId id = rigid_bodies->count++;
274 rigid_bodies->bodies[id] = rect;
275 rigid_bodies->colors[id] = color;
280 Rect rigid_bodies_hitbox(const RigidBodies *rigid_bodies,
283 trace_assert(rigid_bodies);
284 trace_assert(id < rigid_bodies->count);
286 return rigid_bodies->bodies[id];
289 void rigid_bodies_move(RigidBodies *rigid_bodies,
293 trace_assert(rigid_bodies);
294 trace_assert(id < rigid_bodies->count);
296 rigid_bodies->movements[id] = movement;
299 int rigid_bodies_touches_ground(const RigidBodies *rigid_bodies,
302 trace_assert(rigid_bodies);
303 trace_assert(id < rigid_bodies->count);
305 return rigid_bodies->grounded[id];
308 void rigid_bodies_apply_omniforce(RigidBodies *rigid_bodies,
311 for (size_t i = 0; i < rigid_bodies->count; ++i) {
312 rigid_bodies_apply_force(rigid_bodies, i, force);
316 void rigid_bodies_apply_force(RigidBodies * rigid_bodies,
320 trace_assert(rigid_bodies);
321 trace_assert(id < rigid_bodies->count);
323 rigid_bodies->forces[id] = vec_sum(rigid_bodies->forces[id], force);
326 void rigid_bodies_transform_velocity(RigidBodies *rigid_bodies,
330 trace_assert(rigid_bodies);
331 trace_assert(id < rigid_bodies->count);
333 rigid_bodies->velocities[id] = point_mat3x3_product(
334 rigid_bodies->velocities[id],
338 void rigid_bodies_teleport_to(RigidBodies *rigid_bodies,
342 trace_assert(rigid_bodies);
343 trace_assert(id < rigid_bodies->count);
345 rigid_bodies->bodies[id].x = position.x;
346 rigid_bodies->bodies[id].y = position.y;
349 void rigid_bodies_damper(RigidBodies *rigid_bodies,
353 trace_assert(rigid_bodies);
354 trace_assert(id < rigid_bodies->count);
356 rigid_bodies_apply_force(
359 rigid_bodies->velocities[id].x * v.x,
360 rigid_bodies->velocities[id].y * v.y));