From 50957f1b68963fe395746f440cca9d2f6e1f4f7a Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 26 Oct 2020 11:44:12 -0500 Subject: [PATCH] added interactions between different kinds of bodies --- include/physics.h | 16 +++++++++-- src/physics.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++-- src/sim.cpp | 56 ++++++++++++++++++-------------------- 3 files changed, 107 insertions(+), 34 deletions(-) diff --git a/include/physics.h b/include/physics.h index 1044d84..0bf8aef 100644 --- a/include/physics.h +++ b/include/physics.h @@ -4,16 +4,28 @@ #include #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 other_bodies, f64 dt); diff --git a/src/physics.cpp b/src/physics.cpp index 1fae686..93c886d 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -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 other_bodies, V2f d) void body_calculate_move(Body* body, const Array 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 diff --git a/src/sim.cpp b/src/sim.cpp index a58bb09..15083f3 100644 --- a/src/sim.cpp +++ b/src/sim.cpp @@ -146,33 +146,6 @@ create_program(GLuint vertex_shader, GLuint fragment_shader) return program; } - - -struct SimState -{ - Array 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 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 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 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 (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); } -- 2.25.1