diff --git a/platformer.c b/platformer.c index 2db6628..ee0381c 100644 --- a/platformer.c +++ b/platformer.c @@ -29,9 +29,9 @@ static char tilemap[] = " " " " " " " " - "gg " - " " - " " + "gg g " + " g g" + " g " " g " " g g " "gggggggggg"; @@ -49,6 +49,10 @@ static void on_disconnect(void *context) { static bool left_held, right_held, jump_held; +static double jump_maxhold = 0.3; +static double jump_maxheight = 21; +static double jump_duration = 0.4; + static void on_keyboard(void *context, uint32_t window, uint32_t codepoint) { (void) context; if (window != main_window) @@ -62,7 +66,14 @@ static void on_keyboard(void *context, uint32_t window, uint32_t codepoint) { case -KBKEY_RIGHT: right_held = false; break; case KBKEY_SPACE: jump_held = true; break; case -KBKEY_SPACE: jump_held = false; break; + case KBKEY_Q: jump_maxhold += 0.1; break; + case KBKEY_A: jump_maxhold -= 0.1; break; + case KBKEY_W: jump_maxheight += 0.1; break; + case KBKEY_S: jump_maxheight -= 0.1; break; + case KBKEY_E: jump_duration += 0.1; break; + case KBKEY_D: jump_duration -= 0.1; break; } + printf("hold %i height %i duration %i\n", (int)(jump_maxhold * 10), (int)(jump_maxheight * 10), (int)(jump_duration * 10)); } static void on_quit(void *context, uint32_t window) { @@ -91,21 +102,67 @@ static char sample_tilemap(size_t x, size_t y) { return tilemap[ty * TILES + tx]; } -static double player_x, player_y; +static bool jumping = false; +static bool on_ground = false; +static double jump_start_y; +static double in_jump; +static double player_x = 0, player_y = 80; static double player_dx, player_dy; static void update(struct timespec now, struct timespec dt_timespec) { (void) now; double dt = timespec2double(dt_timespec); - player_x += player_dx * dt; - player_y += player_dy * dt; + //player_y += player_dy * dt; if (left_held) player_dx = -30; else if (right_held) player_dx = 30; else player_dx = 0; - if (jump_held) player_dy = -30; - else player_dy = 30; + if (on_ground && jump_held && !jumping) { + jumping = true; + in_jump = 0; + jump_start_y = player_y; + } + if (!on_ground && !jumping) { + // TODO: implement proper falling + jumping = true; + in_jump = jump_duration; + jump_start_y = player_y + jump_maxheight; + } + if (jumping) { + in_jump += dt; + // Jump is a quadratic arc + // h = at^2 + bt + c + // + // Beginning of jump, zero height + // t = 0, h = 0 + // 0 = a0^2 + b0 + c + // c = 0 + // + // At 2*duration, zero height + // t = 2T, h = 0 + // 0 = a(2T)^2 + b(2T) + 0 + // 0 = 4aT^2 + 2bT + // 0 = 2aT^2 + bT + // 0 = 2aT + b + // b = -2aT + // + // At duration, maximum height + // t = T, h = H + // H = aT^2 + bT + 0 + // H = aT^2 - 2aT^2 + // H = -aT^2 + // a = -H / (T^2) + // b + double a = -jump_maxheight / (jump_duration * jump_duration); + double b = -2 * a * jump_duration; + double jump_height = a * in_jump * in_jump + b * in_jump; + player_y = jump_start_y - jump_height; + // player_dy is negative of derivative of jump_height + // H = a*t^2 + b*t + // H' = 2*a*t + b + player_dy = -2 * a * in_jump - b; + } // Collision against walls of the map if (player_x < 0) { @@ -129,7 +186,7 @@ static void update(struct timespec now, struct timespec dt_timespec) { size_t left_cx = px - 1; size_t right_cx = px + TILE_SIDE; size_t leftright_top_cy = py; - size_t leftright_bottom_cy = py + TILE_SIDE - 1; + size_t leftright_bottom_cy = py + TILE_SIDE - 2; if ((sample_tilemap(left_cx, leftright_top_cy) != ' ' || sample_tilemap(left_cx, leftright_bottom_cy) != ' ') && player_dx < 0) { @@ -152,14 +209,15 @@ static void update(struct timespec now, struct timespec dt_timespec) { size_t top_cy = py - 1; size_t bottom_cy = py + TILE_SIDE; - bool on_ground = false; - if ((sample_tilemap(topbottom_left_cx, bottom_cy) != ' ' || - sample_tilemap(topbottom_right_cx, bottom_cy) != ' ') && - player_dy > 0) { + on_ground = false; + if (sample_tilemap(topbottom_left_cx, bottom_cy) != ' ' || + sample_tilemap(topbottom_right_cx, bottom_cy) != ' ') { on_ground = true; - size_t snapped_py = py / TILE_SIDE * TILE_SIDE; - player_y = snapped_py; - player_dy = 0; + if (player_dy > 0) { + jumping = false; + size_t snapped_py = py / TILE_SIDE * TILE_SIDE; + player_y = snapped_py; + } } if ((sample_tilemap(topbottom_left_cx, top_cy) != ' ' || sample_tilemap(topbottom_right_cx, top_cy) != ' ') &&