a-game

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

commit 37f3791a33110ddee4973098008ec3765f9c9389
parent 3a3cd0eae1f1aca6d74ecd94737482d8689a5290
Author: amin <dev@aminmesbah.com>
Date:   Tue, 23 Apr 2019 05:10:33 +0000

Compress that mess

FossilOrigin-Name: d1ec9791b868cb79a3ebe060351644b4e4f1655a02f23e1c31891b24fe80b0df
Diffstat:
Msrc/game.c | 184++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/types.h | 14++++++++++++++
2 files changed, 116 insertions(+), 82 deletions(-)

diff --git a/src/game.c b/src/game.c @@ -76,6 +76,57 @@ internal void game_init(struct GameMemory *game_memory, v2u framebuffer) } } +struct WallCollision +{ + bool collision_occurred; + f32 game_time_offset; + v2 collision_point; +}; + +internal struct WallCollision get_wall_collision(v2 entity_p_initial, v2 entity_p_final, segment wall) +{ + struct WallCollision result = {0}; + result.collision_occurred = false; + + assert(wall.min.x <= wall.max.x); + assert(wall.min.y <= wall.max.y); + + bool wall_is_horizontal = wall.min.y == wall.max.y; + bool wall_is_vertical = wall.min.x == wall.max.x; + assert(wall_is_horizontal || wall_is_vertical); + + enum VectorAxis wall_axis = AXIS_X; + enum VectorAxis wall_normal_axis = AXIS_Y; + if (wall_is_vertical) + { + wall_axis = AXIS_Y; + wall_normal_axis = AXIS_X; + } + + v2 player_delta = glmth_v2_s(entity_p_final, entity_p_initial); + + if (player_delta.E[wall_normal_axis] != 0.0f) + { + f32 wall_position = wall.min.E[wall_normal_axis]; + f32 initial_d = wall.min.E[wall_normal_axis] - entity_p_initial.E[wall_normal_axis]; + + f32 scale_factor = initial_d / player_delta.E[wall_normal_axis]; + v2 collision_point = glmth_v2_a(entity_p_initial, glmth_v2f_m(player_delta, scale_factor)); + + if (scale_factor > 0.0f && scale_factor < 1.0f) + { + if (collision_point.E[wall_axis] >= wall.min.E[wall_axis] + && collision_point.E[wall_axis] <= wall.max.E[wall_axis]) + { + result.collision_occurred = true; + result.collision_point = collision_point; + } + } + } + + return result; +} + // NOTE(amin): For now updating and rendering are interleaved. We simulate the // world at the same rate we render it. Our timestep is not fixed. We may want // to change this in the future. @@ -369,91 +420,60 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga rect tile_player_sum = glmth_minkowski_sum_rect_rect(tile_aabb, player->dimensions); render_debug_quad(game_state, tile_player_sum, (v3) {0.8f, 0.4f, 0.4f}, &view, &projection); - //v2 tile_nw = {tile_player_sum.min.x, tile_player_sum.max.y}; - //v2 tile_ne = tile_player_sum.max; - //v2 tile_sw = tile_player_sum.min; - //v2 tile_se = {tile_player_sum.max.x, tile_player_sum.min.y}; - - //bool hit_bottom = glmth_intersect_segment_segment(old_p, new_p, tile_sw, tile_se); - //bool hit_top = glmth_intersect_segment_segment(old_p, new_p, tile_nw, tile_ne); - //bool hit_left = glmth_intersect_segment_segment(old_p, new_p, tile_sw, tile_nw); - //bool hit_right = glmth_intersect_segment_segment(old_p, new_p, tile_se, tile_ne); - - { // bottom - f32 initial_dist_from_wall = tile_player_sum.min.y - old_p.y; - v2 player_delta = glmth_v2_s(new_p, old_p); - f32 scale_factor = initial_dist_from_wall / player_delta.y; - v2 collision_pos = glmth_v2_a(old_p, glmth_v2f_m(player_delta, scale_factor)); - printf("%f\n", scale_factor); - - if (scale_factor > 0.0f && scale_factor < 1.0f) - { - if (collision_pos.x >= tile_player_sum.min.x && collision_pos.x <= tile_player_sum.max.x) - { - rect collision = { - .min = tile_aabb.min, - .max = {tile_aabb.max.x, tile_aabb.min.y + 0.2f}, - }; - render_debug_quad(game_state, collision, (v3) {1.0f, 0.0f, 0.0f}, &view, &projection); - } - } + v2 tile_nw = {tile_player_sum.min.x, tile_player_sum.max.y}; + v2 tile_ne = tile_player_sum.max; + v2 tile_sw = tile_player_sum.min; + v2 tile_se = {tile_player_sum.max.x, tile_player_sum.min.y}; + + segment tile_b = {tile_sw, tile_se}; + segment tile_t = {tile_nw, tile_ne}; + segment tile_l = {tile_sw, tile_nw}; + segment tile_r = {tile_se, tile_ne}; + + v2 wall_normal = {0}; + + struct WallCollision bottom = get_wall_collision(old_p, new_p, tile_b); + if (bottom.collision_occurred) + { + wall_normal = (v2) {0.0f, -1.0f}; + rect collision = { + .min = tile_aabb.min, + .max = {tile_aabb.max.x, tile_aabb.min.y + 0.2f}, + }; + render_debug_quad(game_state, collision, (v3) {1.0f, 0.0f, 0.0f}, &view, &projection); } - { // top - f32 initial_dist_from_wall = tile_player_sum.max.y - old_p.y; - v2 player_delta = glmth_v2_s(new_p, old_p); - f32 scale_factor = initial_dist_from_wall / player_delta.y; - v2 collision_pos = glmth_v2_a(old_p, glmth_v2f_m(player_delta, scale_factor)); - printf("%f\n", scale_factor); - - if (scale_factor > 0.0f && scale_factor < 1.0f) - { - if (collision_pos.x >= tile_player_sum.min.x && collision_pos.x <= tile_player_sum.max.x) - { - rect collision = { - .min = {tile_aabb.min.x, tile_aabb.max.y - 0.2f}, - .max = tile_aabb.max, - }; - render_debug_quad(game_state, collision, (v3) {0.0f, 1.0f, 0.0f}, &view, &projection); - } - } + + struct WallCollision top = get_wall_collision(old_p, new_p, tile_t); + if (top.collision_occurred) + { + wall_normal = (v2) {0.0f, 1.0f}; + rect collision = { + .min = {tile_aabb.min.x, tile_aabb.max.y - 0.2f}, + .max = tile_aabb.max, + }; + render_debug_quad(game_state, collision, (v3) {0.0f, 1.0f, 0.0f}, &view, &projection); } - { // left - f32 initial_dist_from_wall = tile_player_sum.min.x - old_p.x; - v2 player_delta = glmth_v2_s(new_p, old_p); - f32 scale_factor = initial_dist_from_wall / player_delta.x; - v2 collision_pos = glmth_v2_a(old_p, glmth_v2f_m(player_delta, scale_factor)); - printf("%f\n", scale_factor); - - if (scale_factor > 0.0f && scale_factor < 1.0f) - { - if (collision_pos.y >= tile_player_sum.min.y && collision_pos.y <= tile_player_sum.max.y) - { - rect collision = { - .min = tile_aabb.min, - .max = {tile_aabb.min.x + 0.2f, tile_aabb.max.y}, - }; - render_debug_quad(game_state, collision, (v3) {0.0f, 0.0f, 1.0f}, &view, &projection); - } - } + + struct WallCollision left = get_wall_collision(old_p, new_p, tile_l); + if (left.collision_occurred) + { + wall_normal = (v2) {-1.0f, 0.0f}; + rect collision = { + .min = tile_aabb.min, + .max = {tile_aabb.min.x + 0.2f, tile_aabb.max.y}, + }; + render_debug_quad(game_state, collision, (v3) {0.0f, 0.0f, 1.0f}, &view, &projection); } - { // right - f32 initial_dist_from_wall = tile_player_sum.max.x - old_p.x; - v2 player_delta = glmth_v2_s(new_p, old_p); - f32 scale_factor = initial_dist_from_wall / player_delta.x; - v2 collision_pos = glmth_v2_a(old_p, glmth_v2f_m(player_delta, scale_factor)); - printf("%f\n", scale_factor); - - if (scale_factor > 0.0f && scale_factor < 1.0f) - { - if (collision_pos.y >= tile_player_sum.min.y && collision_pos.y <= tile_player_sum.max.y) - { - rect collision = { - .min = {tile_aabb.max.x - 0.2f, tile_aabb.min.y}, - .max = tile_aabb.max, - }; - render_debug_quad(game_state, collision, (v3) {1.0f, 0.0f, 1.0f}, &view, &projection); - } - } + + struct WallCollision right = get_wall_collision(old_p, new_p, tile_r); + if (right.collision_occurred) + { + wall_normal = (v2) {1.0f, 0.0f}; + rect collision = { + .min = {tile_aabb.max.x - 0.2f, tile_aabb.min.y}, + .max = tile_aabb.max, + }; + render_debug_quad(game_state, collision, (v3) {1.0f, 0.0f, 1.0f}, &view, &projection); } } } diff --git a/src/types.h b/src/types.h @@ -115,7 +115,21 @@ typedef struct typedef struct { + v2 min, max; +} segment; + +typedef struct +{ // row-major, so you probably want to transpose before passing to opengl, // which uses column-major matrices f32 E[4][4]; // E[row][column] } m4; + +enum VectorAxis +{ + AXIS_X = 0, + AXIS_Y = 1, + AXIS_Z = 2, + AXIS_W = 3, + AXIS_MAX = 4, +};