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"
27 static const Vec opposing_rect_side_forces[RECT_SIDE_N] = {
28 { .x = 1.0f, .y = 0.0f }, /* RECT_SIDE_LEFT = 0, */
29 { .x = -1.0f, .y = 0.0f }, /* RECT_SIDE_RIGHT, */
30 { .x = 0.0f, .y = 1.0f, }, /* RECT_SIDE_TOP, */
31 { .x = 0.0f, .y = -1.0f, } /* RECT_SIDE_BOTTOM, */
34 static Vec opposing_force_by_sides(int sides[RECT_SIDE_N])
36 Vec opposing_force = {
41 for (Rect_side side = 0; side < RECT_SIDE_N; ++side) {
45 opposing_rect_side_forces[side]);
49 return opposing_force;
52 RigidBodies *create_rigid_bodies(size_t capacity)
59 RigidBodies *rigid_bodies = PUSH_LT(lt, nth_calloc(1, sizeof(RigidBodies)), free);
60 if (rigid_bodies == NULL) {
63 rigid_bodies->lt = lt;
65 rigid_bodies->capacity = capacity;
66 rigid_bodies->count = 0;
68 rigid_bodies->positions = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
69 if (rigid_bodies->positions == NULL) {
73 rigid_bodies->velocities = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
74 if (rigid_bodies->velocities == NULL) {
78 rigid_bodies->movements = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
79 if (rigid_bodies->movements == NULL) {
83 rigid_bodies->sizes = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
84 if (rigid_bodies->sizes == NULL) {
88 rigid_bodies->colors = PUSH_LT(lt, nth_calloc(capacity, sizeof(Color)), free);
89 if (rigid_bodies->colors == NULL) {
93 rigid_bodies->grounded = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
94 if (rigid_bodies->grounded == NULL) {
98 rigid_bodies->forces = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
99 if (rigid_bodies->forces == NULL) {
106 void destroy_rigid_bodies(RigidBodies *rigid_bodies)
108 trace_assert(rigid_bodies);
109 RETURN_LT0(rigid_bodies->lt);
112 static int rigid_bodies_collide_with_itself(RigidBodies *rigid_bodies)
114 trace_assert(rigid_bodies);
116 if (rigid_bodies->count == 0) {
120 for (size_t i1 = 0; i1 < rigid_bodies->count - 1; ++i1) {
121 for (size_t i2 = i1 + 1; i2 < rigid_bodies->count; ++i2) {
122 // TODO(#653): Rigid Bodies perform too many conversions between rect and two vecs representation
123 // Maybe it's just better to represent the bodies as rects all the time?
124 // TODO(#654): Rigid Bodies don't exchange forces with each other
126 Rect r1 = rect_from_vecs(rigid_bodies->positions[i1], rigid_bodies->sizes[i1]);
127 Rect r2 = rect_from_vecs(rigid_bodies->positions[i2], rigid_bodies->sizes[i2]);
129 if (!rects_overlap(r1, r2)) {
133 rect_impulse(&r1, &r2);
135 rigid_bodies->positions[i1] = vec(r1.x, r1.y);
136 rigid_bodies->sizes[i1] = vec(r1.w, r1.h);
138 rigid_bodies->positions[i2] = vec(r2.x, r2.y);
139 rigid_bodies->sizes[i2] = vec(r2.w, r2.h);
146 static int rigid_bodies_collide_with_platforms(
147 RigidBodies *rigid_bodies,
148 const Platforms *platforms)
150 trace_assert(rigid_bodies);
151 trace_assert(platforms);
153 int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
155 for (size_t i = 0; i < rigid_bodies->count; ++i) {
156 memset(sides, 0, sizeof(int) * RECT_SIDE_N);
158 Rect hitbox = rigid_bodies_hitbox(rigid_bodies, i);
160 platforms_touches_rect_sides(platforms, hitbox, sides);
162 if (sides[RECT_SIDE_BOTTOM]) {
163 rigid_bodies->grounded[i] = true;
166 /* TODO: Opposing force notion in Rigid Bodies seems redundant */
167 Vec opforce_direction = opposing_force_by_sides(sides);
169 if (fabs(opforce_direction.x) > 1e-6 && (opforce_direction.x < 0.0f) != ((rigid_bodies->velocities[i].x + rigid_bodies->movements[i].x) < 0.0f)) {
170 rigid_bodies->velocities[i].x = 0.0f;
171 rigid_bodies->movements[i].x = 0.0f;
174 if (fabs(opforce_direction.y) > 1e-6 && (opforce_direction.y < 0.0f) != ((rigid_bodies->velocities[i].y + rigid_bodies->movements[i].y) < 0.0f)) {
175 rigid_bodies->velocities[i].y = 0.0f;
176 rigid_bodies->movements[i].y = 0.0f;
178 if (vec_length(rigid_bodies->velocities[i]) > 1e-6) {
179 rigid_bodies_apply_force(
182 vec_neg(rigid_bodies->velocities[i]),
187 hitbox = platforms_snap_rect(platforms, hitbox);
188 rigid_bodies->positions[i].x = hitbox.x;
189 rigid_bodies->positions[i].y = hitbox.y;
195 int rigid_bodies_collide(RigidBodies *rigid_bodies,
196 const Platforms *platforms)
198 if (rigid_bodies_collide_with_itself(rigid_bodies) < 0) {
202 if (rigid_bodies_collide_with_platforms(rigid_bodies, platforms) < 0) {
209 int rigid_bodies_update(RigidBodies *rigid_bodies,
212 trace_assert(rigid_bodies);
214 memset(rigid_bodies->grounded, 0,
215 sizeof(bool) * rigid_bodies->count);
217 for (size_t i = 0; i < rigid_bodies->count; ++i) {
218 rigid_bodies->velocities[i] = vec_sum(
219 rigid_bodies->velocities[i],
221 rigid_bodies->forces[i],
225 for (size_t i = 0; i < rigid_bodies->count; ++i) {
226 rigid_bodies->positions[i] = vec_sum(
227 rigid_bodies->positions[i],
230 rigid_bodies->velocities[i],
231 rigid_bodies->movements[i]),
235 memset(rigid_bodies->forces, 0,
236 sizeof(Vec) * rigid_bodies->count);
241 int rigid_bodies_render(RigidBodies *rigid_bodies,
244 trace_assert(rigid_bodies);
245 trace_assert(camera);
247 /* TODO: Rigid Bodies don't render their ids in the debug mode */
249 for (size_t i = 0; i < rigid_bodies->count; ++i) {
250 if (camera_fill_rect(
253 rigid_bodies->positions[i],
254 rigid_bodies->sizes[i]),
255 rigid_bodies->colors[i]) < 0) {
263 RigidBodyId rigid_bodies_add(RigidBodies *rigid_bodies,
267 trace_assert(rigid_bodies);
268 trace_assert(rigid_bodies->count < rigid_bodies->capacity);
270 RigidBodyId id = rigid_bodies->count++;
271 rigid_bodies->positions[id] = vec(rect.x, rect.y);
272 rigid_bodies->sizes[id] = vec(rect.w, rect.h);
273 rigid_bodies->colors[id] = color;
278 Rect rigid_bodies_hitbox(const RigidBodies *rigid_bodies,
281 trace_assert(rigid_bodies);
282 trace_assert(id < rigid_bodies->count);
284 return rect_from_vecs(rigid_bodies->positions[id],
285 rigid_bodies->sizes[id]);
288 void rigid_bodies_move(RigidBodies *rigid_bodies,
292 trace_assert(rigid_bodies);
293 trace_assert(id < rigid_bodies->count);
295 rigid_bodies->movements[id] = movement;
298 int rigid_bodies_touches_ground(const RigidBodies *rigid_bodies,
301 trace_assert(rigid_bodies);
302 trace_assert(id < rigid_bodies->count);
304 return rigid_bodies->grounded[id];
307 void rigid_bodies_apply_omniforce(RigidBodies *rigid_bodies,
310 for (size_t i = 0; i < rigid_bodies->count; ++i) {
311 rigid_bodies_apply_force(rigid_bodies, i, force);
315 void rigid_bodies_apply_force(RigidBodies * rigid_bodies,
319 trace_assert(rigid_bodies);
320 trace_assert(id < rigid_bodies->count);
322 rigid_bodies->forces[id] = vec_sum(rigid_bodies->forces[id], force);
325 void rigid_bodies_transform_velocity(RigidBodies *rigid_bodies,
329 trace_assert(rigid_bodies);
330 trace_assert(id < rigid_bodies->count);
332 rigid_bodies->velocities[id] = point_mat3x3_product(
333 rigid_bodies->velocities[id],
337 void rigid_bodies_teleport_to(RigidBodies *rigid_bodies,
341 trace_assert(rigid_bodies);
342 trace_assert(id < rigid_bodies->count);
344 rigid_bodies->positions[id] = position;
347 void rigid_bodies_damper(RigidBodies *rigid_bodies,
351 trace_assert(rigid_bodies);
352 trace_assert(id < rigid_bodies->count);
354 rigid_bodies_apply_force(
357 rigid_bodies->velocities[id].x * v.x,
358 rigid_bodies->velocities[id].y * v.y));