a-game

2D platformer written from scratch.
git clone git://git.amin.space/a-game.git
Log | Files | Refs | README | LICENSE

commit 80f148c28218a6a83aafe37fbb2e717eb1645b05
parent 736f928759772e12ea59a63b826d60464b39affb
Author: amin <dev@aminmesbah.com>
Date:   Wed, 12 Jun 2019 05:31:11 +0000

Fix the air climbing bug

FossilOrigin-Name: 2fe5cbfcc4a4430c0a56375fd4e4cbf05c3cf4de00151c06a5fccb3a66bd88be
Diffstat:
Msrc/am_math.h | 40+++++++++++++++++++++++++++++++---------
Msrc/game.c | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 101 insertions(+), 19 deletions(-)

diff --git a/src/am_math.h b/src/am_math.h @@ -44,6 +44,12 @@ internal inline i32 math_floor(f32 x) return result; } +internal inline i32 math_ceil(f32 x) +{ + i32 result = ceilf(x); + return result; +} + internal inline f32 math_rand(f32 min, f32 max) { assert(min < max); @@ -511,25 +517,43 @@ internal inline bool math_intersect_aabb_aabb(rect r1, rect r2) return aabbs_do_indeed_intersect; } -internal inline rect math_minkowski_sum_rect_rect(rect r1, v2 r2_dimensions) +internal inline rect math_minkowski_sum_rect(rect r1, v2 r2_dimensions) { - f32 r2_half_w = 0.5f * r2_dimensions.width; - f32 r2_half_h = 0.5f * r2_dimensions.height; + v2 r2_half = { + .width = 0.5f * r2_dimensions.width, + .height = 0.5f * r2_dimensions.height, + }; rect sum = { - .min = {r1.min.x - r2_half_w, r1.min.y - r2_half_h}, - .max = {r1.max.x + r2_half_w, r1.max.y + r2_half_h}, + .min = {r1.min.x - r2_half.width, r1.min.y - r2_half.height}, + .max = {r1.max.x + r2_half.width, r1.max.y + r2_half.height}, }; return sum; } +internal inline rect math_minkowski_diff_rect(rect r1, v2 r2_dimensions) +{ + v2 negated_r2_dim = math_v2_negate(r2_dimensions); + rect difference = math_minkowski_sum_rect(r1, negated_r2_dim); + return difference; +} + +internal inline rect math_rect_from_center_dim(v2 center, v2 dimensions) +{ + v2 half_d = {dimensions.x * 0.5f, dimensions.y * 0.5f}; + rect result = { + .min = {center.x - half_d.x, center.y - half_d.y}, + .max = {center.x + half_d.x, center.y + half_d.y}, + }; + return result; +} + enum MathRectEdge { RECT_EDGE_BOTTOM, RECT_EDGE_TOP, RECT_EDGE_LEFT, RECT_EDGE_RIGHT, - - NUM_RECT_EDGES, + MAX_RECT_EDGE, }; internal inline segment math_rect_get_edge(rect r, enum MathRectEdge e) @@ -554,7 +578,6 @@ internal inline segment math_rect_get_edge(rect r, enum MathRectEdge e) case RECT_EDGE_RIGHT: edge = (segment) {se, ne}; break; - case NUM_RECT_EDGES: // fallthrough default: assert(false); break; @@ -579,7 +602,6 @@ internal v2 math_rect_get_normal(enum MathRectEdge e) case RECT_EDGE_RIGHT: normal = (v2) {1.0f, 0.0f}; break; - case NUM_RECT_EDGES: // fallthrough default: assert(false); break; diff --git a/src/game.c b/src/game.c @@ -234,7 +234,53 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga } else if (player->move_state == MOVE_STATE_CLIMBING) { - if (player->facing == previous_facing_dir) + bool player_is_still_next_to_wall = true; + rect player_rect = math_rect_from_center_dim(player->pos.local, player->dimensions); + v2 next_tile_top = {0}; + v2 next_tile_bottom = {0}; + if (player->facing == DIR_LEFT) + { + next_tile_top = (v2) {math_floor(player_rect.min.x - 1.0f), math_floor(player_rect.max.y)}; + next_tile_bottom = (v2) {math_floor(player_rect.min.x - 1.0f), math_floor(player_rect.min.y)}; + } + else if (player->facing == DIR_RIGHT) + { + next_tile_top = (v2) {math_ceil(player_rect.max.x), math_floor(player_rect.max.y)}; + next_tile_bottom = (v2) {math_ceil(player_rect.max.x), math_floor(player_rect.min.y)}; + } + else + { + assert(false); + } + renderer_debug_quad_draw( + &game_state->renderer, + (rect) { + .min = next_tile_top, + .max = {next_tile_top.x + TILE_SIZE, next_tile_top.y + TILE_SIZE}, + }, + (v3) {1.0f, 0.0f, 1.0f}); + renderer_debug_quad_draw( + &game_state->renderer, + (rect) { + .min = next_tile_bottom, + .max = {next_tile_bottom.x + TILE_SIZE, next_tile_bottom.y + TILE_SIZE}, + }, + (v3) {1.0f, 0.0f, 1.0f}); + + rect player_room_bounds = math_minkowski_diff_rect( + (rect) {.min = {0.0f, 0.0f}, .max = {ROOM_TILE_DIM_X, ROOM_TILE_DIM_Y}}, + player->dimensions); + + if (math_in_interval_open(player->pos.local.x, player_room_bounds.min.x, player_room_bounds.max.x) + && math_in_interval_open(player->pos.local.y, player_room_bounds.min.y, player_room_bounds.max.y)) + { + if (!tile_is_solid(current_room->tiles, next_tile_top) && !tile_is_solid(current_room->tiles, next_tile_bottom)) + { + player_is_still_next_to_wall = false; + } + } + + if (player_is_still_next_to_wall && player->facing == previous_facing_dir) { if (game_input->key_up) { @@ -256,8 +302,15 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga } } else if (player->move_state == MOVE_STATE_GROUNDED - || player->move_state == MOVE_STATE_CLIMBING - || player->move_state == MOVE_STATE_JUMPING) + || player->move_state == MOVE_STATE_CLIMBING) + { + if (game_input->key_jump) + { + player->acceleration.y = acceleration_rate; + player->move_state = MOVE_STATE_JUMPING; + } + } + else if (player->move_state == MOVE_STATE_JUMPING) { if (game_input->key_jump) { @@ -266,6 +319,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga } else { + player->acceleration.y = -acceleration_rate; player->move_state = MOVE_STATE_FALLING; } } @@ -279,7 +333,11 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga // game_detect_collisions { +#if 0 #define RENDER_COLLISION_DEBUG_QUAD(r, c) renderer_debug_quad_draw(&game_state->renderer, (r), (c)); +#else +#define RENDER_COLLISION_DEBUG_QUAD(r, c) +#endif v2 player_delta = math_v2f_m(player->velocity, dt); v2 new_p = math_v2_a(player->pos.local, player_delta); @@ -288,7 +346,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga .max = {math_max(player->pos.local.x, new_p.x), math_max(player->pos.local.y, new_p.y)}, }; - rect player_traversal_occupancy_bb = math_minkowski_sum_rect_rect(player_traversal_bb, player->dimensions); + rect player_traversal_occupancy_bb = math_minkowski_sum_rect(player_traversal_bb, player->dimensions); rect tile_search_range = { .min = { @@ -309,7 +367,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga v2 wall_normal = {0}; f32 smallest_distance_scale_factor = 1.0f; bool collision_occurred = false; - enum MathRectEdge collided_edge = 0; + bool edges_collided[MAX_RECT_EDGE] = {0}; for (i32 tile_y = tile_search_range.min.y; tile_y < tile_search_range.max.y; tile_y++) { for (i32 tile_x = tile_search_range.min.x; tile_x < tile_search_range.max.x; tile_x++) @@ -345,9 +403,9 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga }; RENDER_COLLISION_DEBUG_QUAD(tile_aabb, ((v3) {0.8f, 0.4f, 0.4f})); - rect tile_player_sum = math_minkowski_sum_rect_rect(tile_aabb, player->dimensions); + rect tile_player_sum = math_minkowski_sum_rect(tile_aabb, player->dimensions); - for (enum MathRectEdge edge = 0; edge < NUM_RECT_EDGES; edge++) + for (enum MathRectEdge edge = 0; edge < MAX_RECT_EDGE; edge++) { segment player_sum_wall = math_rect_get_edge(tile_player_sum, edge); v2 normal = math_rect_get_normal(edge); @@ -359,10 +417,10 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga if (c.collision_occurred) { collision_occurred = true; + edges_collided[edge] = true; if (smallest_distance_scale_factor > c.distance_scale_factor) { smallest_distance_scale_factor = c.distance_scale_factor; - collided_edge = edge; } wall_normal = normal; RENDER_COLLISION_DEBUG_QUAD( @@ -380,12 +438,14 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga if (collision_occurred) { - if (collided_edge == RECT_EDGE_TOP && player->move_state == MOVE_STATE_FALLING) + if (edges_collided[RECT_EDGE_TOP] && player->move_state == MOVE_STATE_FALLING) { + printf("Noo! I am stuck on the ground!"); player->move_state = MOVE_STATE_GROUNDED; } - else if (collided_edge == RECT_EDGE_LEFT || collided_edge == RECT_EDGE_RIGHT) + else if (edges_collided[RECT_EDGE_LEFT] || edges_collided[RECT_EDGE_RIGHT]) { + printf("Yay! I can climb now!"); player->move_state = MOVE_STATE_CLIMBING; } }