added interactions between different kinds of bodies
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 26 Oct 2020 16:44:12 +0000 (11:44 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 26 Oct 2020 16:44:12 +0000 (11:44 -0500)
include/physics.h
src/physics.cpp
src/sim.cpp

index 1044d84b87fbb4d715b3021e3fd5c59dc2b37804..0bf8aef7109c29c4f1df37632e252d331d9a484d 100644 (file)
@@ -4,16 +4,28 @@
 #include <vecmath.h>
 #include "container.h"
 
+typedef u8 BodyType;
+enum
+{
+    BodyType_Red    = 0,
+    BodyType_Green  = 1,
+    BodyType_Blue   = 2,
+    BodyType_White  = 3,
+    
+    BodyType_Count
+};
+
 struct Body
 {
     V2f pos;
     V2f vel;
+    V2f acc;
     
-    V2f post_update_vel;
+    V2f move_vec;
     
     f32 mass;
     
-    u8 color_idx;
+    BodyType body_type;
 };
 
 void body_calculate_move(Body* body, const Array<Body> other_bodies, f64 dt);
index 1fae686c63b9575d17c47ca17179c88727965a4e..93c886d3080d45100d0949a3029da9f382901258 100644 (file)
@@ -2,6 +2,48 @@
 #include "utils.h"
 #include "types.h"
 
+// NOTE(Brendan): This represents the piecewise function:
+//
+// F(d) = {
+//     0 < d < 1:                      (1 / d) - 1
+//     1 <= d < distance_range + 1:    (-4 * max_force / (distance_range ^ 2)) * (d - (distance_range / 2) - 1) ^ 2 + max_force,
+//     otherwise:                      0
+//
+struct BodyRelation
+{
+    f32 distance_range;
+    f32 max_force;
+};
+
+internal f32
+get_force_magnitude_at_distance(BodyRelation br, f32 d)
+{
+    if (0 < d && d < 1)
+    {
+        return (1 / d) - 1;
+    }
+    
+    if (1 <= d && d < br.distance_range + 1)
+    {
+        f32 tmp_x = d - (br.distance_range / 2) - 1;
+        
+        return (-4 * br.max_force / (br.distance_range * br.distance_range))
+            * (tmp_x * tmp_x)
+            + br.max_force;
+    }
+    
+    return 0;
+}
+
+internal const
+BodyRelation body_relations[BodyType_Count][BodyType_Count] = {
+    //              Red             Green           Blue            White
+    /* Red */   { { 1.0f, 2.0f }, { 0.0f, 0.0f }, { 5.0f, -2.0f }, { 0.0f, 0.0f } },
+    /* Green */ { { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f } },
+    /* Blue */  { { 2.0f, 3.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f } },
+    /* White */ { { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f } },
+};
+
 internal bool
 bodies_collide(Body* b1, Body* b2)
 {
@@ -30,17 +72,40 @@ body_can_move(Body* body, const Array<Body> other_bodies, V2f d)
 void
 body_calculate_move(Body* body, const Array<Body> other_bodies, f64 dt)
 {
-    body->post_update_vel = V2f { 0.0f, 0.0f, };
+    // NOTE(Brendan): Old code for moving bodies randomly with collisions.
+    /* body->post_update_vel = V2f { 0.0f, 0.0f, };
     
     if (body_can_move(body, other_bodies, V2f { (f32) (body->vel.x * dt), 0.0f }))
         body->post_update_vel.x += body->vel.x * dt;
     
     if (body_can_move(body, other_bodies, V2f { 0.0f, (f32) (body->vel.y * dt) }))
         body->post_update_vel.y += body->vel.y * dt;
+*/
+    
+    V2f force = { 0.0f, 0.0f };
+    
+    For (other_bodies)
+    {
+        if (body == &it) continue;
+        
+        auto norm_dir = body->pos - it.pos;
+        auto d = v2f_mag(norm_dir) / 25.0f;
+        norm_dir = v2f_norm(norm_dir);
+        
+        f32 force_mag = get_force_magnitude_at_distance(body_relations[body->body_type][it.body_type], d);
+        
+        force += norm_dir * force_mag;
+    }
+    
+    force += body->vel * -5.f;
+    
+    body->acc = force * (1.0f / body->mass);
+    body->vel += body->acc * dt;
+    body->move_vec = body->vel;
 }
 
 void
 body_apply_move(Body* body)
 {
-    body->pos += body->post_update_vel;
+    body->pos += body->move_vec;
 }
\ No newline at end of file
index a58bb093920cf67e7907b12dc80ed3c491438f36..15083f3db29fbd5248c9d1ddd94c0fa932b782e8 100644 (file)
@@ -146,33 +146,6 @@ create_program(GLuint vertex_shader, GLuint fragment_shader)
     return program;
 }
 
-
-
-struct SimState
-{
-    Array<Body> bodies;
-};
-
-internal void
-sim_state_init(SimState* state)
-{
-    // NOTE(Brendan): Need to initialize the array since it does not get constructed because I refuse to use the 'new' keyword. alloc<T> uses malloc under the hood and cannot initialize the result.
-    state->bodies.init();
-    state->bodies.ensure_capacity(1024);
-    
-    foreach (i, 0, 1024)
-    {
-        Body tmp_body;
-        tmp_body.pos = V2f{ randf(0, 800), randf(0, 800) };
-        tmp_body.vel = V2f{ randf(-50.0f, 50.0f), randf(-50.0f, 50.0f) };
-        tmp_body.mass = randf(2.0f, 10.0f);
-        tmp_body.color_idx = rand() % 4;
-        state->bodies.push(tmp_body);
-    }
-}
-
-
-
 #define CIRCLE_POINT_COUNT 36 // NOTE(Brendan): Treat a circle as a many-sided polygon.
 
 // NOTE(Brendan): Returns the VAO where the mesh data was bound.
@@ -214,16 +187,39 @@ create_circle_mesh()
     return vao;
 }
 
+struct SimState
+{
+    Array<Body> bodies;
+};
+
+internal void
+sim_state_init(SimState* state)
+{
+    // NOTE(Brendan): Need to initialize the array since it does not get constructed because I refuse to use the 'new' keyword. alloc<T> uses malloc under the hood and cannot initialize the result.
+    state->bodies.init();
+    state->bodies.ensure_capacity(1024);
+    
+    foreach (i, 0, 1024)
+    {
+        Body tmp_body;
+        tmp_body.pos = V2f{ randf(0, 800), randf(0, 800) };
+        tmp_body.vel = V2f{ 0.0f, 0.0f };
+        tmp_body.mass = randf(2.0f, 10.0f);
+        tmp_body.body_type = static_cast<BodyType> (rand() % 2) * 2;
+        state->bodies.push(tmp_body);
+    }
+}
+
 // NOTE(Brendan): dt is expected to be in units of "per second".
 internal void
 update(SimState* state, f64 dt)
 {
     For (state->bodies)
     {
-        if (rand() % 50 == 0)
+        /*if (rand() % 50 == 0)
         {
             it.vel = V2f{ randf(-50.0f, 50.0f), randf(-50.0f, 50.0f) };
-        }
+        }*/
         
         body_calculate_move(&it, state->bodies, dt);
     }
@@ -333,7 +329,7 @@ main(i32 argc, char* argv[])
         }
         glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof(Body), (void *) offsetof(Body, pos.x));
         glVertexAttribPointer(2, 1, GL_FLOAT, false, sizeof(Body), (void *) offsetof(Body, mass));
-        glVertexAttribPointer(3, 1, GL_BYTE, false, sizeof(Body), (void *) offsetof(Body, color_idx));
+        glVertexAttribPointer(3, 1, GL_BYTE, false, sizeof(Body), (void *) offsetof(Body, body_type));
         
         glBindBuffer(GL_ARRAY_BUFFER, -1);
     }