7 #include "game/level/boxes.h"
8 #include "game/level/solid.h"
9 #include "math/minmax.h"
10 #include "rigid_rect.h"
11 #include "system/error.h"
12 #include "system/lt.h"
14 #define MAX_ID_SIZE 36
15 #define STRINGIFY(x) STRINGIFY2(x)
16 #define STRINGIFY2(x) #x
30 static const Vec opposing_rect_side_forces[RECT_SIDE_N] = {
31 { .x = 1.0f, .y = 0.0f }, /* RECT_SIDE_LEFT = 0, */
32 { .x = -1.0f, .y = 0.0f }, /* RECT_SIDE_RIGHT, */
33 { .x = 0.0f, .y = 1.0f, }, /* RECT_SIDE_TOP, */
34 { .x = 0.0f, .y = -1.0f, } /* RECT_SIDE_BOTTOM, */
37 static Vec opposing_force_by_sides(int sides[RECT_SIDE_N])
39 Vec opposing_force = {
44 for (Rect_side side = 0; side < RECT_SIDE_N; ++side) {
48 opposing_rect_side_forces[side]);
52 return opposing_force;
55 Rigid_rect *create_rigid_rect(Rect rect, Color color, const char *id)
65 Rigid_rect *rigid_rect = PUSH_LT(lt, malloc(sizeof(Rigid_rect)), free);
66 if (rigid_rect == NULL) {
67 throw_error(ERROR_TYPE_LIBC);
72 rigid_rect->id = malloc(sizeof(char) * MAX_ID_SIZE);
73 if (rigid_rect->id == NULL) {
74 throw_error(ERROR_TYPE_LIBC);
78 const size_t len_id = min_size(MAX_ID_SIZE - 1, strlen(id));
79 memcpy(rigid_rect->id, id, len_id);
80 rigid_rect->id[len_id] = 0;
82 rigid_rect->position = vec(rect.x, rect.y);
83 rigid_rect->velocity = vec(0.0f, 0.0f);
84 rigid_rect->movement = vec(0.0f, 0.0f);
85 rigid_rect->size = vec(rect.w, rect.h);
86 rigid_rect->color = color;
87 rigid_rect->touches_ground = 0;
88 rigid_rect->forces = vec(0.0f, 0.0f);
93 Rigid_rect *create_rigid_rect_from_stream(FILE *stream)
101 if (fscanf(stream, "%" STRINGIFY(MAX_ID_SIZE) "s%f%f%f%f%6s\n",
106 throw_error(ERROR_TYPE_LIBC);
110 return create_rigid_rect(rect, color_from_hexstr(color), id);
113 void destroy_rigid_rect(Rigid_rect *rigid_rect)
115 RETURN_LT0(rigid_rect->lt);
118 Solid_ref rigid_rect_as_solid(Rigid_rect *rigid_rect)
120 const Solid_ref ref = {
121 .tag = SOLID_RIGID_RECT,
128 void rigid_rect_touches_rect_sides(Rigid_rect *rigid_rect,
130 int sides[RECT_SIDE_N])
132 rect_object_impact(object, rigid_rect_hitbox(rigid_rect), sides);
135 int rigid_rect_render(const Rigid_rect *rigid_rect,
138 if (camera_fill_rect(
140 rigid_rect_hitbox(rigid_rect),
141 rigid_rect->color) < 0) {
148 int rigid_rect_update(Rigid_rect * rigid_rect,
153 rigid_rect->touches_ground = 0;
155 /* TODO(#207): rigid_rect floating in lava is broken */
156 rigid_rect->velocity = vec_sum(
157 rigid_rect->velocity,
162 rigid_rect->position = vec_sum(
163 rigid_rect->position,
166 rigid_rect->velocity,
167 rigid_rect->movement),
170 rigid_rect->forces = vec(0.0f, 0.0f);
175 void rigid_rect_collide_with_solid(Rigid_rect * rigid_rect,
179 assert(rigid_rect != solid.ptr);
181 int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
183 solid_touches_rect_sides(solid, rigid_rect_hitbox(rigid_rect), sides);
185 if (sides[RECT_SIDE_BOTTOM]) {
186 rigid_rect->touches_ground = 1;
189 Vec opforce_direction = opposing_force_by_sides(sides);
194 vec_neg(vec_norm(opforce_direction)),
197 rigid_rect->velocity,
198 rigid_rect->movement)) * 8.0f));
200 if (fabs(opforce_direction.x) > 1e-6 && (opforce_direction.x < 0.0f) != ((rigid_rect->velocity.x + rigid_rect->movement.x) < 0.0f)) {
201 rigid_rect->velocity.x = 0.0f;
202 rigid_rect->movement.x = 0.0f;
205 if (fabs(opforce_direction.y) > 1e-6 && (opforce_direction.y < 0.0f) != ((rigid_rect->velocity.y + rigid_rect->movement.y) < 0.0f)) {
206 rigid_rect->velocity.y = 0.0f;
207 rigid_rect->movement.y = 0.0f;
209 if (vec_length(rigid_rect->velocity) > 1e-6) {
210 rigid_rect_apply_force(
213 vec_neg(rigid_rect->velocity),
219 for (int i = 0; i < 1000 && vec_length(opforce_direction) > 1e-6; ++i) {
220 rigid_rect->position = vec_sum(
221 rigid_rect->position,
226 memset(sides, 0, sizeof(int) * RECT_SIDE_N);
227 solid_touches_rect_sides(
229 rigid_rect_hitbox(rigid_rect),
231 opforce_direction = opposing_force_by_sides(sides);
235 Rect rigid_rect_hitbox(const Rigid_rect *rigid_rect)
237 return rect_from_vecs(
238 rigid_rect->position,
242 void rigid_rect_move(Rigid_rect *rigid_rect,
245 rigid_rect->movement = movement;
248 int rigid_rect_touches_ground(const Rigid_rect *rigid_rect)
250 return rigid_rect->touches_ground;
253 void rigid_rect_apply_force(Rigid_rect * rigid_rect,
256 rigid_rect->forces = vec_sum(rigid_rect->forces, force);
259 void rigid_rect_transform_velocity(Rigid_rect *rigid_rect,
262 rigid_rect->velocity = point_mat3x3_product(rigid_rect->velocity,
266 void rigid_rect_teleport_to(Rigid_rect *rigid_rect,
269 rigid_rect->position = position;
272 void rigid_rect_damper(Rigid_rect *rigid_rect, Vec v)
274 rigid_rect_apply_force(
276 vec(rigid_rect->velocity.x * v.x, rigid_rect->velocity.y * v.y));
279 bool rigid_rect_has_id(Rigid_rect *rigid_rect,
285 return strcmp(rigid_rect->id, id) == 0;