diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-12-08 19:31:42 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-12-08 19:31:42 -0500 |
commit | 806db25561bd23a52ccaa09af727bd26ea04fb41 (patch) | |
tree | f8f57a3b2dbd52257a75a17ba67f23a25f3fe714 | |
parent | 798727229c3f27de4b4a81c6168d0f12a3094b72 (diff) |
moving platforms, rotating platforms, consistent physics
-rw-r--r-- | assets/platform_f.glsl | 5 | ||||
-rw-r--r-- | sim.cpp | 110 | ||||
-rw-r--r-- | sim.hpp | 18 |
3 files changed, 88 insertions, 45 deletions
diff --git a/assets/platform_f.glsl b/assets/platform_f.glsl index 82c8740..7877ff5 100644 --- a/assets/platform_f.glsl +++ b/assets/platform_f.glsl @@ -9,9 +9,8 @@ void main() { float h = clamp(dot(pos-p1, p2-p1) / dot(p2-p1, p2-p1), 0.0, 1.0); float d = length(pos - p1 - (p2-p1) * h); - float v = max(thickness - d, 0.0); - v /= thickness; - v *= v; + d /= thickness; + float v = 1.0 - d * d; gl_FragColor = color * v; } @@ -170,11 +170,11 @@ static void shaders_reload_if_necessary(State *state) { static void platforms_render(State *state, Platform *platforms, u32 nplatforms) { GL *gl = &state->gl; ShaderPlatform *shader = &state->shader_platform; - float thickness = state->platform_thickness; + float platform_render_thickness = state->platform_thickness; shader_start_using(gl, &shader->base); - gl->Uniform1f(shader->uniform_thickness, thickness); + gl->Uniform1f(shader->uniform_thickness, platform_render_thickness); gl->UniformMatrix4fv(shader->uniform_transform, 1, GL_FALSE, state->transform.e); glBegin(GL_QUADS); @@ -182,7 +182,7 @@ static void platforms_render(State *state, Platform *platforms, u32 nplatforms) for (Platform *platform = platforms, *end = platform + nplatforms; platform != end; ++platform) { float radius = platform->size * 0.5f; v2 center = platform->center; - v2 thickness_r = v2_polar(state->platform_thickness, platform->angle - HALF_PIf); + v2 thickness_r = v2_polar(platform_render_thickness, platform->angle - HALF_PIf); v2 platform_r = v2_polar(radius, platform->angle); v2 endpoint1 = v2_add(center, platform_r); v2 endpoint2 = v2_sub(center, platform_r); @@ -228,10 +228,15 @@ static void ball_render(State *state) { } -static b2Body *platform_to_body(State *state, Platform *platform) { +// sets platform->body to a new Box2D body. +static void platform_make_body(State *state, Platform *platform) { b2World *world = state->world; float half_size = platform->size * 0.5f; + + if (platform->moves) + platform->center = platform->move_p1; + v2 center = platform->center; b2BodyDef body_def; @@ -243,9 +248,43 @@ static b2Body *platform_to_body(State *state, Platform *platform) { b2PolygonShape shape; shape.SetAsBox(half_size, state->platform_thickness); body->CreateFixture(&shape, 0.0f); - body->SetLinearVelocity(b2Vec2(0, 3.0f)); - body->SetAngularVelocity(2.0f); - return body; + if (platform->moves) { + float speed = platform->move_speed; + v2 p1 = platform->move_p1, p2 = platform->move_p2; + v2 direction = v2_normalize(v2_sub(p2, p1)); + v2 velocity = v2_scale(direction, speed); + body->SetLinearVelocity(v2_to_b2(velocity)); + } + body->SetAngularVelocity(platform->rotate_speed); + + platform->body = body; +} + +static void simulate_time(State *state, float dt) { + float time_step = 0.01f; // fixed time step + dt += state->time_residue; + while (dt >= time_step) { + Ball *ball = &state->ball; + b2World *world = state->world; + + world->Step(time_step, 8, 3); // step using recommended parameters + + if (ball->body) { + b2Vec2 ball_pos = ball->body->GetPosition(); + + if (ball_pos.y - ball->radius < state->bottom_y) { + // oh no! ball reached bottom line + world->DestroyBody(ball->body); + ball->body = NULL; + ball->pos.y = state->bottom_y + ball->radius; + } else { + ball->pos = b2_to_v2(ball_pos); + } + } + + dt -= time_step; + } + state->time_residue = dt; } #ifdef __cplusplus @@ -330,15 +369,15 @@ void sim_frame(Frame *frame) { shaders_load(state); - state->platform_thickness = 0.15f; + state->platform_thickness = 0.05f; state->bottom_y = 0.1f; text_font_load(state, &state->font, "assets/font.ttf", 36.0f); - ball->radius = 0.6f; + ball->radius = 0.3f; ball->pos = V2(0, 10.0f); - b2Vec2 gravity(0, -30.0f); + b2Vec2 gravity(0, -9.81f); b2World *world = state->world = new b2World(gravity); // create ground @@ -370,15 +409,19 @@ void sim_frame(Frame *frame) { { // initialize platforms state->nplatforms = 2; Platform *p = &state->platforms[0]; - p->center = V2(0, 0.5f); - p->angle = PIf * 0.46f; + p->center = V2(0, 0.8f); + p->angle = 0; p->size = 9.0f; - p->body = platform_to_body(state, p); + p->rotate_speed = 1.0f; + platform_make_body(state, p); ++p; - p->center = V2(0, 0.5f); + p->moves = true; + p->move_p1 = V2(0, 0.5f); + p->move_p2 = V2(0, 5.5f); + p->move_speed = 1.0f; p->angle = PIf * 0.54f; p->size = 6.0f; - p->body = platform_to_body(state, p); + platform_make_body(state, p); } state->initialized = true; @@ -395,31 +438,14 @@ void sim_frame(Frame *frame) { shaders_reload_if_necessary(state); #endif - b2World *world = state->world; + maybe_unused b2World *world = state->world; Font *font = &state->font; // simulate physics { - float time_step = 0.01f; // fixed time step float dt = state->dt; if (dt > 100) dt = 100; // prevent floating-point problems for very large dt's - while (dt >= time_step) { - world->Step(time_step, 8, 3); // step using recommended parameters - dt -= time_step; - } - if (ball->body) { - b2Vec2 ball_pos = ball->body->GetPosition(); - ball->pos.x = ball_pos.x; - ball->pos.y = ball_pos.y; - - if (ball_pos.y - ball->radius < state->bottom_y) { - // oh no! ball reached bottom line - world->DestroyBody(ball->body); - ball->body = NULL; - } else { - state->distance_traveled = ball_pos.x; - } - } + simulate_time(state, dt); for (Platform *platform = state->platforms, *end = platform + state->nplatforms; platform != end; ++platform) { b2Vec2 platform_pos = platform->body->GetPosition(); platform->center = b2_to_v2(platform_pos); @@ -436,7 +462,7 @@ void sim_frame(Frame *frame) { } platforms_render(state, state->platforms, state->nplatforms); - if (ball->body) ball_render(state); + ball_render(state); { v3 line_pos = V3(0, state->bottom_y, 0); @@ -456,11 +482,17 @@ void sim_frame(Frame *frame) { } { - char text[256] = {0}; + char x_text[64] = {0}, y_text[64] = {0}; glColor3f(0.8f,0.5f,1); - snprintf(text, sizeof text - 1, "Distance: %.2f m", state->distance_traveled); - v2 size = text_get_size(state, font, text); - text_render(state, font, text, v2_sub(V2(0.95f, 0.95f), size)); + snprintf(x_text, sizeof x_text - 1, "x: %.2f m", ball->pos.x); + snprintf(y_text, sizeof y_text - 1, "y: %.2f m", ball->pos.y); + v2 x_size = text_get_size(state, font, x_text); + v2 y_size = text_get_size(state, font, y_text); + v2 pos = V2(0.95f, 0.95f); + text_render(state, font, x_text, v2_sub(pos, x_size)); + pos.y -= x_size.y; + text_render(state, font, y_text, v2_sub(pos, y_size)); + pos.y -= y_size.y; } #if DEBUG @@ -127,9 +127,18 @@ typedef struct { typedef struct { b2Body *body; - v2 center; + v2 center; // NOTE: when creating a moving platform, you don't need to set this (it will be automatically initialized to move_pos1) float size; float angle; + + bool moves; // does this platform move? + + // if it's a moving platform + float move_speed; + v2 move_p1; + v2 move_p2; + + float rotate_speed; } Platform; typedef struct { @@ -144,6 +153,11 @@ typedef struct { i32 win_width, win_height; // width,height of window float dt; // time in seconds since last frame + + // physics time left unsimulated last frame + // (we need to always pass Box2D the same dt for consistency, so there + // will be some left over, if the frame time is not a multiple of the fixed time step) + float time_residue; m4 transform; // the transform for converting our coordinates to GL coordinates GL gl; // gl functions @@ -155,8 +169,6 @@ typedef struct { Ball ball; float bottom_y; // if y goes below here, it's over - float distance_traveled; - Font font; float platform_thickness; |