]> git.lizzy.rs Git - nothing.git/blobdiff - src/game/level/rigid_bodies.c
(#819) Integrate LevelEditor Regions with Level
[nothing.git] / src / game / level / rigid_bodies.c
index f301f9a0808fdc25487f112bd9f16a91ebd876df..db5484e00757985ea66cf545905387938c4c4fb2 100644 (file)
@@ -9,33 +9,29 @@
 #include "system/line_stream.h"
 #include "system/str.h"
 #include "system/log.h"
+#include "hashset.h"
 
 #include "./rigid_bodies.h"
 
-#define ID_SIZE 100
-#define RIGID_BODIES_MAX_ID_SIZE 36
-
 struct RigidBodies
 {
     Lt *lt;
-    // TODO: capacity is not needed in RigidBodies
     size_t capacity;
     size_t count;
 
     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) {
@@ -61,11 +57,6 @@ RigidBodies *create_rigid_bodies(size_t capacity)
         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);
@@ -76,6 +67,27 @@ RigidBodies *create_rigid_bodies(size_t capacity)
         RETURN_LT(lt, NULL);
     }
 
+    rigid_bodies->deleted = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
+    if (rigid_bodies->deleted == 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;
 }
 
@@ -93,21 +105,64 @@ static int rigid_bodies_collide_with_itself(RigidBodies *rigid_bodies)
         return 0;
     }
 
-    for (size_t i1 = 0; i1 < rigid_bodies->count - 1; ++i1) {
-        for (size_t i2 = i1 + 1; i2 < rigid_bodies->count; ++i2) {
-            if (!rects_overlap(rigid_bodies->bodies[i1], rigid_bodies->bodies[i2])) {
+    size_t pair[2];
+    hashset_clear(rigid_bodies->collided);
+
+    bool the_variable_that_gets_set_when_a_collision_happens_xd = true;
+
+    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;
+                }
 
-            const Vec v1 = rigid_bodies->velocities[i1];
-            const Vec v2 = rigid_bodies->velocities[i2];
-            rigid_bodies->velocities[i1] = v2;
-            rigid_bodies->velocities[i2] = v1;
+                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);
+
+            }
         }
     }
 
+    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;
 }
 
@@ -121,6 +176,10 @@ static int rigid_bodies_collide_with_platforms(
     int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
 
     for (size_t i = 0; i < rigid_bodies->count; ++i) {
+        if (rigid_bodies->deleted[i] || rigid_bodies->disabled[i]) {
+            continue;
+        }
+
         memset(sides, 0, sizeof(int) * RECT_SIDE_N);
 
         platforms_touches_rect_sides(platforms, rigid_bodies->bodies[i], sides);
@@ -161,6 +220,10 @@ int rigid_bodies_update(RigidBodies *rigid_bodies,
 {
     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(
@@ -188,21 +251,26 @@ int rigid_bodies_update(RigidBodies *rigid_bodies,
 
 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;
     }
 
-    snprintf(text_buffer, ID_SIZE, "id: %ld", id);
+    snprintf(text_buffer, 256, "id: %ld", id);
 
     if (camera_render_debug_text(
             camera,
@@ -212,7 +280,7 @@ int rigid_bodies_render(RigidBodies *rigid_bodies,
         return -1;
     }
 
-    snprintf(text_buffer, 256, "pos:(%f, %f)",
+    snprintf(text_buffer, 256, "p:(%.2f, %.2f)",
              rigid_bodies->bodies[id].x,
              rigid_bodies->bodies[id].y);
     if (camera_render_debug_text(
@@ -223,46 +291,50 @@ int rigid_bodies_render(RigidBodies *rigid_bodies,
         return -1;
     }
 
+    snprintf(text_buffer, 256, "v:(%.2f, %.2f)",
+             rigid_bodies->velocities[id].x,
+             rigid_bodies->velocities[id].y);
+    if (camera_render_debug_text(
+            camera,
+            text_buffer,
+            vec(rigid_bodies->bodies[id].x,
+                rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 4.0f))) {
+        return -1;
+    }
+
+    snprintf(text_buffer, 256, "m:(%.2f, %.2f)",
+             rigid_bodies->movements[id].x,
+             rigid_bodies->movements[id].y);
+    if (camera_render_debug_text(
+            camera,
+            text_buffer,
+            vec(rigid_bodies->bodies[id].x,
+                rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 6.0f))) {
+        return -1;
+    }
+
     return 0;
 }
 
 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;
 }
 
-RigidBodyId rigid_bodies_add_from_line_stream(RigidBodies *rigid_bodies,
-                                              LineStream *line_stream)
+void rigid_bodies_remove(RigidBodies *rigid_bodies,
+                         RigidBodyId id)
 {
     trace_assert(rigid_bodies);
-    trace_assert(line_stream);
-
-    char color[7];
-    Rect rect;
-    // TODO: 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: rigid_bodies_add_from_line_stream cannot indicate an error properly
-        return 0;
-    }
+    trace_assert(id < rigid_bodies->capacity);
 
-    return rigid_bodies_add(rigid_bodies, rect, hexstr(color));
+    rigid_bodies->deleted[id] = true;
 }
 
 Rect rigid_bodies_hitbox(const RigidBodies *rigid_bodies,
@@ -281,6 +353,10 @@ void rigid_bodies_move(RigidBodies *rigid_bodies,
     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;
 }
 
@@ -308,6 +384,10 @@ void rigid_bodies_apply_force(RigidBodies * rigid_bodies,
     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);
 }
 
@@ -318,6 +398,10 @@ void rigid_bodies_transform_velocity(RigidBodies *rigid_bodies,
     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);
@@ -330,6 +414,10 @@ void rigid_bodies_teleport_to(RigidBodies *rigid_bodies,
     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;
 }
@@ -341,9 +429,23 @@ void rigid_bodies_damper(RigidBodies *rigid_bodies,
     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;
+}