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 int rigid_bodies_collide_with_itself(RigidBodies *rigid_bodies)
114 trace_assert(rigid_bodies);
116 /* TODO(#647): rigid_bodies_collide_with_itself is not implemented */
121 int rigid_bodies_collide_with_platforms(
122 RigidBodies *rigid_bodies,
123 const Platforms *platforms)
125 trace_assert(rigid_bodies);
126 trace_assert(platforms);
128 int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
130 for (size_t i = 0; i < rigid_bodies->count; ++i) {
131 memset(sides, 0, sizeof(int) * RECT_SIDE_N);
133 platforms_touches_rect_sides(platforms, rigid_bodies_hitbox(rigid_bodies, i), sides);
135 if (sides[RECT_SIDE_BOTTOM]) {
136 rigid_bodies->grounded[i] = true;
139 Vec opforce_direction = opposing_force_by_sides(sides);
141 /* It's an opposing force that we apply to platforms. But
142 * since platforms are impenetrable, it's not needed
143 * here. Plus we are trying to apply that force to the rigid
144 * body itself, because I'm dumb. */
146 rigid_bodies_apply_force(
149 vec_neg(vec_norm(opforce_direction)),
151 vec_sum(rigid_bodies->velocities[i],
152 rigid_bodies->movements[i])) * 8.0f));
155 if (fabs(opforce_direction.x) > 1e-6 && (opforce_direction.x < 0.0f) != ((rigid_bodies->velocities[i].x + rigid_bodies->movements[i].x) < 0.0f)) {
156 rigid_bodies->velocities[i].x = 0.0f;
157 rigid_bodies->movements[i].x = 0.0f;
160 if (fabs(opforce_direction.y) > 1e-6 && (opforce_direction.y < 0.0f) != ((rigid_bodies->velocities[i].y + rigid_bodies->movements[i].y) < 0.0f)) {
161 rigid_bodies->velocities[i].y = 0.0f;
162 rigid_bodies->movements[i].y = 0.0f;
164 if (vec_length(rigid_bodies->velocities[i]) > 1e-6) {
165 rigid_bodies_apply_force(
168 vec_neg(rigid_bodies->velocities[i]),
173 for (int j = 0; j < 1000 && vec_length(opforce_direction) > 1e-6; ++j) {
174 rigid_bodies->positions[i] = vec_sum(
175 rigid_bodies->positions[i],
180 memset(sides, 0, sizeof(int) * RECT_SIDE_N);
181 platforms_touches_rect_sides(platforms, rigid_bodies_hitbox(rigid_bodies, i), sides);
182 opforce_direction = opposing_force_by_sides(sides);
189 int rigid_bodies_update(RigidBodies *rigid_bodies,
192 trace_assert(rigid_bodies);
194 memset(rigid_bodies->grounded, 0,
195 sizeof(bool) * rigid_bodies->count);
197 for (size_t i = 0; i < rigid_bodies->count; ++i) {
198 rigid_bodies->velocities[i] = vec_sum(
199 rigid_bodies->velocities[i],
201 rigid_bodies->forces[i],
205 for (size_t i = 0; i < rigid_bodies->count; ++i) {
206 rigid_bodies->positions[i] = vec_sum(
207 rigid_bodies->positions[i],
210 rigid_bodies->velocities[i],
211 rigid_bodies->movements[i]),
215 memset(rigid_bodies->forces, 0,
216 sizeof(Vec) * rigid_bodies->count);
221 int rigid_bodies_render(RigidBodies *rigid_bodies,
224 trace_assert(rigid_bodies);
225 trace_assert(camera);
227 for (size_t i = 0; i < rigid_bodies->count; ++i) {
228 if (camera_fill_rect(
231 rigid_bodies->positions[i],
232 rigid_bodies->sizes[i]),
233 rigid_bodies->colors[i]) < 0) {
241 RigidBodyId rigid_bodies_add(RigidBodies *rigid_bodies,
245 trace_assert(rigid_bodies);
246 trace_assert(rigid_bodies->count < rigid_bodies->capacity);
248 RigidBodyId id = rigid_bodies->count++;
249 rigid_bodies->positions[id] = vec(rect.x, rect.y);
250 rigid_bodies->sizes[id] = vec(rect.w, rect.h);
251 rigid_bodies->colors[id] = color;
256 Rect rigid_bodies_hitbox(const RigidBodies *rigid_bodies,
259 trace_assert(rigid_bodies);
260 trace_assert(id < rigid_bodies->count);
262 return rect_from_vecs(rigid_bodies->positions[id],
263 rigid_bodies->sizes[id]);
266 void rigid_bodies_move(RigidBodies *rigid_bodies,
270 trace_assert(rigid_bodies);
271 trace_assert(id < rigid_bodies->count);
273 rigid_bodies->movements[id] = movement;
276 int rigid_bodies_touches_ground(const RigidBodies *rigid_bodies,
279 trace_assert(rigid_bodies);
280 trace_assert(id < rigid_bodies->count);
282 return rigid_bodies->grounded[id];
285 void rigid_bodies_apply_omniforce(RigidBodies *rigid_bodies,
288 for (size_t i = 0; i < rigid_bodies->count; ++i) {
289 rigid_bodies_apply_force(rigid_bodies, i, force);
293 void rigid_bodies_apply_force(RigidBodies * rigid_bodies,
297 trace_assert(rigid_bodies);
298 trace_assert(id < rigid_bodies->count);
300 rigid_bodies->forces[id] = vec_sum(rigid_bodies->forces[id], force);
303 void rigid_bodies_transform_velocity(RigidBodies *rigid_bodies,
307 trace_assert(rigid_bodies);
308 trace_assert(id < rigid_bodies->count);
310 rigid_bodies->velocities[id] = point_mat3x3_product(
311 rigid_bodies->velocities[id],
315 void rigid_bodies_teleport_to(RigidBodies *rigid_bodies,
319 trace_assert(rigid_bodies);
320 trace_assert(id < rigid_bodies->count);
322 rigid_bodies->positions[id] = position;
325 void rigid_bodies_damper(RigidBodies *rigid_bodies,
329 trace_assert(rigid_bodies);
330 trace_assert(id < rigid_bodies->count);
332 rigid_bodies_apply_force(
335 rigid_bodies->velocities[id].x * v.x,
336 rigid_bodies->velocities[id].y * v.y));