]> git.lizzy.rs Git - nothing.git/blobdiff - src/game/level/rigid_bodies.c
(#1142) Top-left resize snapping
[nothing.git] / src / game / level / rigid_bodies.c
index 4b8e248def1af9f9f0296b40952d5cc0c55b81f3..667916e87fc7b5cf9e31688f1454b001e0fe6555 100644 (file)
@@ -6,6 +6,10 @@
 #include "system/lt.h"
 #include "system/nth_alloc.h"
 #include "system/stacktrace.h"
+#include "system/line_stream.h"
+#include "system/str.h"
+#include "system/log.h"
+#include "hashset.h"
 
 #include "./rigid_bodies.h"
 
@@ -15,46 +19,18 @@ struct RigidBodies
     size_t capacity;
     size_t count;
 
-    Vec *positions;
-    Vec *velocities;
-    Vec *movements;
-    Vec *sizes;
-    Color *colors;
+    Rect *bodies;
+    Vec2f *velocities;
+    Vec2f *movements;
     bool *grounded;
-    Vec *forces;
+    Vec2f *forces;
+    bool *deleted;
+    bool *disabled;
 };
 
-static const Vec opposing_rect_side_forces[RECT_SIDE_N] = {
-    { .x = 1.0f,  .y =  0.0f  },  /* RECT_SIDE_LEFT = 0, */
-    { .x = -1.0f, .y =  0.0f  },  /* RECT_SIDE_RIGHT, */
-    { .x = 0.0f,  .y =  1.0f, },  /* RECT_SIDE_TOP, */
-    { .x = 0.0f,  .y = -1.0f, }   /* RECT_SIDE_BOTTOM, */
-};
-
-static Vec opposing_force_by_sides(int sides[RECT_SIDE_N])
-{
-    Vec opposing_force = {
-        .x = 0.0f,
-        .y = 0.0f
-    };
-
-    for (Rect_side side = 0; side < RECT_SIDE_N; ++side) {
-        if (sides[side]) {
-            vec_add(
-                &opposing_force,
-                opposing_rect_side_forces[side]);
-        }
-    }
-
-    return opposing_force;
-}
-
 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) {
@@ -65,38 +41,41 @@ RigidBodies *create_rigid_bodies(size_t capacity)
     rigid_bodies->capacity = capacity;
     rigid_bodies->count = 0;
 
-    rigid_bodies->positions = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
-    if (rigid_bodies->positions == NULL) {
+    rigid_bodies->bodies = PUSH_LT(lt, nth_calloc(capacity, sizeof(Rect)), free);
+    if (rigid_bodies->bodies == NULL) {
         RETURN_LT(lt, NULL);
     }
 
-    rigid_bodies->velocities = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
+    rigid_bodies->velocities = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec2f)), free);
     if (rigid_bodies->velocities == NULL) {
         RETURN_LT(lt, NULL);
     }
 
-    rigid_bodies->movements = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
+    rigid_bodies->movements = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec2f)), free);
     if (rigid_bodies->movements == NULL) {
         RETURN_LT(lt, NULL);
     }
 
-    rigid_bodies->sizes = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
-    if (rigid_bodies->sizes == NULL) {
+    rigid_bodies->grounded = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
+    if (rigid_bodies->grounded == NULL) {
         RETURN_LT(lt, NULL);
     }
 
-    rigid_bodies->colors = PUSH_LT(lt, nth_calloc(capacity, sizeof(Color)), free);
-    if (rigid_bodies->colors == NULL) {
+    rigid_bodies->forces = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec2f)), free);
+    if (rigid_bodies->forces == NULL) {
         RETURN_LT(lt, NULL);
     }
 
-    rigid_bodies->grounded = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
-    if (rigid_bodies->grounded == NULL) {
+    rigid_bodies->deleted = PUSH_LT(lt, nth_calloc(capacity, sizeof(bool)), free);
+    if (rigid_bodies->deleted == NULL) {
         RETURN_LT(lt, NULL);
     }
 
-    rigid_bodies->forces = PUSH_LT(lt, nth_calloc(capacity, sizeof(Vec)), free);
-    if (rigid_bodies->forces == NULL) {
+    rigid_bodies->disabled = PUSH_LT(
+        lt,
+        nth_calloc(capacity, sizeof(bool)),
+        free);
+    if (rigid_bodies->disabled == NULL) {
         RETURN_LT(lt, NULL);
     }
 
@@ -109,178 +88,228 @@ void destroy_rigid_bodies(RigidBodies *rigid_bodies)
     RETURN_LT0(rigid_bodies->lt);
 }
 
-static int rigid_bodies_collide_with_itself(RigidBodies *rigid_bodies)
+int rigid_bodies_collide(RigidBodies *rigid_bodies,
+                         const Platforms *platforms)
 {
-    trace_assert(rigid_bodies);
+    memset(rigid_bodies->grounded, 0, sizeof(bool) * rigid_bodies->count);
 
-    for (size_t i1 = 0; i1 < rigid_bodies->count - 1; ++i1) {
-        for (size_t i2 = i1 + 1; i2 < rigid_bodies->count; ++i2) {
-            Rect r1 = rect_from_vecs(rigid_bodies->positions[i1], rigid_bodies->sizes[i1]);
-            Rect r2 = rect_from_vecs(rigid_bodies->positions[i2], rigid_bodies->sizes[i2]);
+    if (rigid_bodies->count == 0) {
+        return 0;
+    }
 
-            if (!rects_overlap(r1, r2)) {
-                continue;
-            }
+    int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
 
-            rect_impulse(&r1, &r2);
 
-            rigid_bodies->positions[i1] = vec(r1.x, r1.y);
-            rigid_bodies->sizes[i1] = vec(r1.w, r1.h);
+    int t = 100;
+    int the_variable_that_gets_set_when_a_collision_happens_xd = 1;
+    while (t-- > 0 && the_variable_that_gets_set_when_a_collision_happens_xd) {
+        the_variable_that_gets_set_when_a_collision_happens_xd = 0;
 
-            rigid_bodies->positions[i2] = vec(r2.x, r2.y);
-            rigid_bodies->sizes[i2] = vec(r2.w, r2.h);
-        }
-    }
+        for (size_t i1 = 0; i1 < rigid_bodies->count; ++i1) {
+            if (rigid_bodies->deleted[i1] || rigid_bodies->disabled[i1]) {
+                continue;
+            }
 
-    return 0;
-}
+            // Platforms
+            memset(sides, 0, sizeof(int) * RECT_SIDE_N);
 
-static int rigid_bodies_collide_with_platforms(
-    RigidBodies *rigid_bodies,
-    const Platforms *platforms)
-{
-    trace_assert(rigid_bodies);
-    trace_assert(platforms);
+            platforms_touches_rect_sides(platforms, rigid_bodies->bodies[i1], sides);
 
-    int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
+            for (int i = 0; i < RECT_SIDE_N; ++i) {
+                if (sides[i]) {
+                    the_variable_that_gets_set_when_a_collision_happens_xd = 1;
+                }
+            }
 
-    for (size_t i = 0; i < rigid_bodies->count; ++i) {
-        memset(sides, 0, sizeof(int) * RECT_SIDE_N);
+            if (sides[RECT_SIDE_BOTTOM]) {
+                rigid_bodies->grounded[i1] = true;
+            }
+
+            Vec2f v = platforms_snap_rect(platforms, &rigid_bodies->bodies[i1]);
+            rigid_bodies->velocities[i1] = vec_entry_mult(rigid_bodies->velocities[i1], v);
+            rigid_bodies->movements[i1] = vec_entry_mult(rigid_bodies->movements[i1], v);
+            rigid_bodies_damper(rigid_bodies, i1, vec_entry_mult(v, vec(-16.0f, 0.0f)));
 
-        Rect hitbox = rigid_bodies_hitbox(rigid_bodies, i);
+            if (i1 >= rigid_bodies->count - 1) {
+                continue;
+            }
 
-        platforms_touches_rect_sides(platforms, hitbox, sides);
+            // Self-collision
+            for (size_t i2 = i1 + 1; i2 < rigid_bodies->count; ++i2) {
+                if (rigid_bodies->deleted[i2] || rigid_bodies->disabled[i1]) {
+                    continue;
+                }
 
-        if (sides[RECT_SIDE_BOTTOM]) {
-            rigid_bodies->grounded[i] = true;
-        }
+                if (!rects_overlap(rigid_bodies->bodies[i1], rigid_bodies->bodies[i2])) {
+                    continue;
+                }
 
-        Vec opforce_direction = opposing_force_by_sides(sides);
+                the_variable_that_gets_set_when_a_collision_happens_xd = 1;
 
-        if (fabs(opforce_direction.x) > 1e-6 && (opforce_direction.x < 0.0f) != ((rigid_bodies->velocities[i].x + rigid_bodies->movements[i].x) < 0.0f)) {
-            rigid_bodies->velocities[i].x = 0.0f;
-            rigid_bodies->movements[i].x = 0.0f;
-        }
+                Vec2f orient = rect_impulse(&rigid_bodies->bodies[i1], &rigid_bodies->bodies[i2]);
 
-        if (fabs(opforce_direction.y) > 1e-6 && (opforce_direction.y < 0.0f) != ((rigid_bodies->velocities[i].y + rigid_bodies->movements[i].y) < 0.0f)) {
-            rigid_bodies->velocities[i].y = 0.0f;
-            rigid_bodies->movements[i].y = 0.0f;
+                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;
+                    }
+                }
 
-            if (vec_length(rigid_bodies->velocities[i]) > 1e-6) {
-                rigid_bodies_apply_force(
-                    rigid_bodies, i,
-                    vec_scala_mult(
-                        vec_neg(rigid_bodies->velocities[i]),
-                        16.0f));
+                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);
             }
         }
-
-        hitbox = platforms_snap_rect(platforms, hitbox);
-        rigid_bodies->positions[i].x = hitbox.x;
-        rigid_bodies->positions[i].y = hitbox.y;
-    }
-
-    return 0;
-}
-
-int rigid_bodies_collide(RigidBodies *rigid_bodies,
-                         const Platforms *platforms)
-{
-    if (rigid_bodies_collide_with_itself(rigid_bodies) < 0) {
-        return -1;
-    }
-
-    if (rigid_bodies_collide_with_platforms(rigid_bodies, platforms) < 0) {
-        return -1;
     }
 
     return 0;
 }
 
 int rigid_bodies_update(RigidBodies *rigid_bodies,
+                        RigidBodyId id,
                         float delta_time)
 {
     trace_assert(rigid_bodies);
 
-    memset(rigid_bodies->grounded, 0,
-           sizeof(bool) * rigid_bodies->count);
-
-    for (size_t i = 0; i < rigid_bodies->count; ++i) {
-        rigid_bodies->velocities[i] = vec_sum(
-            rigid_bodies->velocities[i],
-            vec_scala_mult(
-                rigid_bodies->forces[i],
-                delta_time));
+    if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
+        return 0;
     }
 
-    for (size_t i = 0; i < rigid_bodies->count; ++i) {
-        rigid_bodies->positions[i] = vec_sum(
-            rigid_bodies->positions[i],
+    rigid_bodies->velocities[id] = vec_sum(
+            rigid_bodies->velocities[id],
             vec_scala_mult(
-                vec_sum(
-                    rigid_bodies->velocities[i],
-                    rigid_bodies->movements[i]),
+                rigid_bodies->forces[id],
                 delta_time));
-    }
 
-    memset(rigid_bodies->forces, 0,
-           sizeof(Vec) * rigid_bodies->count);
+    Vec2f position = vec(rigid_bodies->bodies[id].x,
+                       rigid_bodies->bodies[id].y);
+
+    position = vec_sum(
+        position,
+        vec_scala_mult(
+            vec_sum(
+                rigid_bodies->velocities[id],
+                rigid_bodies->movements[id]),
+            delta_time));
+
+    rigid_bodies->bodies[id].x = position.x;
+    rigid_bodies->bodies[id].y = position.y;
+
+    rigid_bodies->forces[id] = vec(0.0f, 0.0f);
 
     return 0;
 }
 
 int rigid_bodies_render(RigidBodies *rigid_bodies,
-                        Camera *camera)
+                        RigidBodyId id,
+                        Color color,
+                        const Camera *camera)
 {
     trace_assert(rigid_bodies);
     trace_assert(camera);
 
-    for (size_t i = 0; i < rigid_bodies->count; ++i) {
-        if (camera_fill_rect(
-                camera,
-                rect_from_vecs(
-                    rigid_bodies->positions[i],
-                    rigid_bodies->sizes[i]),
-                rigid_bodies->colors[i]) < 0) {
-            return -1;
-        }
+    if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
+        return 0;
+    }
+
+    char text_buffer[256];
+
+    if (camera_fill_rect(
+            camera,
+            rigid_bodies->bodies[id],
+            color) < 0) {
+        return -1;
+    }
+
+    snprintf(text_buffer, 256, "id: %zd", id);
+
+    if (camera_render_debug_text(
+            camera,
+            text_buffer,
+            vec(rigid_bodies->bodies[id].x,
+                rigid_bodies->bodies[id].y)) < 0) {
+        return -1;
+    }
+
+    snprintf(text_buffer, 256, "p:(%.2f, %.2f)",
+             rigid_bodies->bodies[id].x,
+             rigid_bodies->bodies[id].y);
+    if (camera_render_debug_text(
+            camera,
+            text_buffer,
+            vec(rigid_bodies->bodies[id].x,
+                rigid_bodies->bodies[id].y + FONT_CHAR_HEIGHT * 2.0f))) {
+        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->positions[id] = vec(rect.x, rect.y);
-    rigid_bodies->sizes[id] = vec(rect.w, rect.h);
-    rigid_bodies->colors[id] = color;
+    rigid_bodies->bodies[id] = rect;
 
     return id;
 }
 
+void rigid_bodies_remove(RigidBodies *rigid_bodies,
+                         RigidBodyId id)
+{
+    trace_assert(rigid_bodies);
+    trace_assert(id < rigid_bodies->capacity);
+
+    rigid_bodies->deleted[id] = true;
+}
+
 Rect rigid_bodies_hitbox(const RigidBodies *rigid_bodies,
                          RigidBodyId id)
 {
     trace_assert(rigid_bodies);
     trace_assert(id < rigid_bodies->count);
 
-    return rect_from_vecs(rigid_bodies->positions[id],
-                          rigid_bodies->sizes[id]);
+    return rigid_bodies->bodies[id];
 }
 
 void rigid_bodies_move(RigidBodies *rigid_bodies,
                        RigidBodyId id,
-                       Vec movement)
+                       Vec2f movement)
 {
     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;
 }
 
@@ -294,7 +323,7 @@ int rigid_bodies_touches_ground(const RigidBodies *rigid_bodies,
 }
 
 void rigid_bodies_apply_omniforce(RigidBodies *rigid_bodies,
-                                  Vec force)
+                                  Vec2f force)
 {
     for (size_t i = 0; i < rigid_bodies->count; ++i) {
         rigid_bodies_apply_force(rigid_bodies, i, force);
@@ -303,11 +332,15 @@ void rigid_bodies_apply_omniforce(RigidBodies *rigid_bodies,
 
 void rigid_bodies_apply_force(RigidBodies * rigid_bodies,
                               RigidBodyId id,
-                              Vec force)
+                              Vec2f force)
 {
     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 +351,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);
@@ -325,24 +362,43 @@ void rigid_bodies_transform_velocity(RigidBodies *rigid_bodies,
 
 void rigid_bodies_teleport_to(RigidBodies *rigid_bodies,
                               RigidBodyId id,
-                              Vec position)
+                              Vec2f position)
 {
     trace_assert(rigid_bodies);
     trace_assert(id < rigid_bodies->count);
 
-    rigid_bodies->positions[id] = position;
+    if (rigid_bodies->deleted[id] || rigid_bodies->disabled[id]) {
+        return;
+    }
+
+    rigid_bodies->bodies[id].x = position.x;
+    rigid_bodies->bodies[id].y = position.y;
 }
 
 void rigid_bodies_damper(RigidBodies *rigid_bodies,
                          RigidBodyId id,
-                         Vec v)
+                         Vec2f v)
 {
     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;
+}