#include "system/line_stream.h"
#include "system/str.h"
#include "system/log.h"
+#include "hashset.h"
#include "./rigid_bodies.h"
-#define RIGID_BODIES_MAX_ID_SIZE 36
-
struct RigidBodies
{
Lt *lt;
Rect *bodies;
Vec *velocities;
Vec *movements;
- Color *colors;
bool *grounded;
Vec *forces;
bool *deleted;
+ HashSet *collided;
+ bool *disabled;
};
RigidBodies *create_rigid_bodies(size_t capacity)
{
Lt *lt = create_lt();
- if (lt == NULL) {
- return NULL;
- }
RigidBodies *rigid_bodies = PUSH_LT(lt, nth_calloc(1, sizeof(RigidBodies)), free);
if (rigid_bodies == NULL) {
RETURN_LT(lt, NULL);
}
- rigid_bodies->colors = PUSH_LT(lt, nth_calloc(capacity, sizeof(Color)), free);
- if (rigid_bodies->colors == NULL) {
- RETURN_LT(lt, NULL);
- }
-
rigid_bodies->grounded = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
if (rigid_bodies->grounded == NULL) {
RETURN_LT(lt, NULL);
RETURN_LT(lt, NULL);
}
+ rigid_bodies->collided = PUSH_LT(
+ lt,
+ create_hashset(sizeof(size_t) * 2, capacity * 2),
+ destroy_hashset);
+ if (rigid_bodies->collided == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ rigid_bodies->disabled = PUSH_LT(
+ lt,
+ nth_calloc(capacity, sizeof(bool)),
+ free);
+ if (rigid_bodies->disabled == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
return rigid_bodies;
}
return 0;
}
- for (size_t i1 = 0; i1 < rigid_bodies->count - 1; ++i1) {
- if (rigid_bodies->deleted[i1]) {
- continue;
- }
+ size_t pair[2];
+ hashset_clear(rigid_bodies->collided);
- for (size_t i2 = i1 + 1; i2 < rigid_bodies->count; ++i2) {
- if (rigid_bodies->deleted[i2]) {
- continue;
- }
+ bool the_variable_that_gets_set_when_a_collision_happens_xd = true;
- if (!rects_overlap(rigid_bodies->bodies[i1], rigid_bodies->bodies[i2])) {
+ for (size_t i = 0; i < 1000 && the_variable_that_gets_set_when_a_collision_happens_xd; ++i) {
+ the_variable_that_gets_set_when_a_collision_happens_xd = false;
+ for (size_t i1 = 0; i1 < rigid_bodies->count - 1; ++i1) {
+ if (rigid_bodies->deleted[i1] || rigid_bodies->disabled[i1]) {
continue;
}
- rect_impulse(&rigid_bodies->bodies[i1], &rigid_bodies->bodies[i2]);
+ for (size_t i2 = i1 + 1; i2 < rigid_bodies->count; ++i2) {
+ if (rigid_bodies->deleted[i2] || rigid_bodies->disabled[i1]) {
+ continue;
+ }
+
+ if (!rects_overlap(rigid_bodies->bodies[i1], rigid_bodies->bodies[i2])) {
+ continue;
+ }
+
+ the_variable_that_gets_set_when_a_collision_happens_xd = true;
+
+ pair[0] = i1;
+ pair[1] = i2;
+ hashset_insert(rigid_bodies->collided, pair);
+
+ Vec orient = rect_impulse(&rigid_bodies->bodies[i1], &rigid_bodies->bodies[i2]);
+
+ if (orient.x > orient.y) {
+ if (rigid_bodies->bodies[i1].y < rigid_bodies->bodies[i2].y) {
+ rigid_bodies->grounded[i1] = true;
+ } else {
+ rigid_bodies->grounded[i2] = true;
+ }
+ }
+
+ rigid_bodies->velocities[i1] = vec(rigid_bodies->velocities[i1].x * orient.x, rigid_bodies->velocities[i1].y * orient.y);
+ rigid_bodies->velocities[i2] = vec(rigid_bodies->velocities[i2].x * orient.x, rigid_bodies->velocities[i2].y * orient.y);
+ rigid_bodies->movements[i1] = vec(rigid_bodies->movements[i1].x * orient.x, rigid_bodies->movements[i1].y * orient.y);
+ rigid_bodies->movements[i2] = vec(rigid_bodies->movements[i2].x * orient.x, rigid_bodies->movements[i2].y * orient.y);
- const Vec v1 = rigid_bodies->velocities[i1];
- const Vec v2 = rigid_bodies->velocities[i2];
- rigid_bodies->velocities[i1] = v2;
- rigid_bodies->velocities[i2] = v1;
+ }
}
}
+ size_t *collided = hashset_values(rigid_bodies->collided);
+ const size_t n = hashset_count(rigid_bodies->collided);
+ for (size_t i = 0; i < n; ++i) {
+ const size_t i1 = *(collided + i * 2);
+ const size_t i2 = *(collided + i * 2 + 1);
+
+ rigid_bodies_apply_force(
+ rigid_bodies, i1, vec_sum(rigid_bodies->velocities[i2], rigid_bodies->movements[i2]));
+ rigid_bodies_apply_force(
+ rigid_bodies, i2, vec_sum(rigid_bodies->velocities[i1], rigid_bodies->movements[i1]));
+ }
+
return 0;
}
int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
for (size_t i = 0; i < rigid_bodies->count; ++i) {
- if (rigid_bodies->deleted[i]) {
+ if (rigid_bodies->deleted[i] || rigid_bodies->disabled[i]) {
continue;
}
{
trace_assert(rigid_bodies);
+ if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
+ return 0;
+ }
+
rigid_bodies->velocities[id] = vec_sum(
rigid_bodies->velocities[id],
vec_scala_mult(
int rigid_bodies_render(RigidBodies *rigid_bodies,
RigidBodyId id,
+ Color color,
Camera *camera)
{
trace_assert(rigid_bodies);
trace_assert(camera);
+ if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
+ return 0;
+ }
+
char text_buffer[256];
if (camera_fill_rect(
camera,
rigid_bodies->bodies[id],
- rigid_bodies->colors[id]) < 0) {
+ color) < 0) {
return -1;
}
}
RigidBodyId rigid_bodies_add(RigidBodies *rigid_bodies,
- Rect rect,
- Color color)
+ Rect rect)
{
trace_assert(rigid_bodies);
trace_assert(rigid_bodies->count < rigid_bodies->capacity);
RigidBodyId id = rigid_bodies->count++;
rigid_bodies->bodies[id] = rect;
- rigid_bodies->colors[id] = color;
return id;
}
rigid_bodies->deleted[id] = true;
}
-RigidBodyId rigid_bodies_add_from_line_stream(RigidBodies *rigid_bodies,
- LineStream *line_stream)
-{
- trace_assert(rigid_bodies);
- trace_assert(line_stream);
-
- char color[7];
- Rect rect;
- // TODO(#686): id should be part of boxes
- char id[RIGID_BODIES_MAX_ID_SIZE];
-
- if (sscanf(line_stream_next(line_stream),
- "%" STRINGIFY(RIGID_BODIES_MAX_ID_SIZE) "s%f%f%f%f%6s\n",
- id,
- &rect.x, &rect.y,
- &rect.w, &rect.h,
- color) < 0) {
- log_fail("Could not read rigid rect\n");
- // TODO(#687): rigid_bodies_add_from_line_stream cannot indicate an error properly
- return 0;
- }
-
- return rigid_bodies_add(rigid_bodies, rect, hexstr(color));
-}
-
Rect rigid_bodies_hitbox(const RigidBodies *rigid_bodies,
RigidBodyId id)
{
trace_assert(rigid_bodies);
trace_assert(id < rigid_bodies->count);
+ if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
+ return;
+ }
+
rigid_bodies->movements[id] = movement;
}
trace_assert(rigid_bodies);
trace_assert(id < rigid_bodies->count);
+ if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
+ return;
+ }
+
rigid_bodies->forces[id] = vec_sum(rigid_bodies->forces[id], force);
}
trace_assert(rigid_bodies);
trace_assert(id < rigid_bodies->count);
+ if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
+ return;
+ }
+
rigid_bodies->velocities[id] = point_mat3x3_product(
rigid_bodies->velocities[id],
trans_mat);
trace_assert(rigid_bodies);
trace_assert(id < rigid_bodies->count);
+ if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
+ return;
+ }
+
rigid_bodies->bodies[id].x = position.x;
rigid_bodies->bodies[id].y = position.y;
}
trace_assert(rigid_bodies);
trace_assert(id < rigid_bodies->count);
+ if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
+ return;
+ }
+
rigid_bodies_apply_force(
rigid_bodies, id,
vec(
rigid_bodies->velocities[id].x * v.x,
rigid_bodies->velocities[id].y * v.y));
}
+
+void rigid_bodies_disable(RigidBodies *rigid_bodies,
+ RigidBodyId id,
+ bool disabled)
+{
+ trace_assert(rigid_bodies);
+ trace_assert(id < rigid_bodies->count);
+
+ rigid_bodies->disabled[id] = disabled;
+}