a-game

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

commit 41c2e6ed9f56bf284f097164cf05d708746a9c02
parent ca65e8820cee92715af2d7ceef5560321f0ccbb4
Author: amin <dev@aminmesbah.com>
Date:   Thu, 25 Apr 2019 03:24:21 +0000

Use tile face normals during collision

This might not be totally necessary. It allows the player to move out of
a solid tile if they happen to be in one.

FossilOrigin-Name: acfe114f5190b51ba0f318e785974f3003b1f1490e2d81a32e31baa374b215d9
Diffstat:
Msrc/game.c | 48++++++++++++++++++++++++++++++------------------
1 file changed, 30 insertions(+), 18 deletions(-)

diff --git a/src/game.c b/src/game.c @@ -15,6 +15,7 @@ internal void game_init(struct GameMemory *game_memory, v2u framebuffer) // init player game_state->player.pos = (v2) {12.5f, 5.0f}; + game_state->player.pos = (v2) {12.5f, 8.5f}; // In Knytt, the player is 9 by 14 texels and a tile is 24 by 24 texels. // These dimensions are relative to a square 'meter', one tile @@ -80,7 +81,8 @@ struct WallCollision f32 distance_scale_factor; }; -internal struct WallCollision get_wall_collision(v2 entity_p_initial, v2 entity_p_final, segment wall) +internal struct WallCollision get_wall_collision(v2 entity_p_initial, v2 entity_p_final, segment wall, v2 wall_normal) + { struct WallCollision result = {0}; result.collision_occurred = false; @@ -102,7 +104,15 @@ internal struct WallCollision get_wall_collision(v2 entity_p_initial, v2 entity_ v2 player_delta = glmth_v2_s(entity_p_final, entity_p_initial); - if (player_delta.E[wall_normal_axis] != 0.0f) + // NOTE(amin): We needn't normalize player_delta here because its magnitude + // becomes irrelevant as the value of cos(theta) nears zero, and we are + // concerned only about the behavior near pi/2 and 3pi/2, where cos(theta) + // is zero. Therefore we simply treat player_delta as if it _were_ + // normalized. + f32 cos_theta = glmth_v2_dot(player_delta, wall_normal); + + bool theta_is_obtuse = cos_theta < 0.0f; + if (theta_is_obtuse) { f32 wall_position = wall.min.E[wall_normal_axis]; f32 initial_d = wall_position - entity_p_initial.E[wall_normal_axis]; @@ -115,12 +125,8 @@ internal struct WallCollision get_wall_collision(v2 entity_p_initial, v2 entity_ if (collision_point.E[wall_axis] >= wall.min.E[wall_axis] && collision_point.E[wall_axis] <= wall.max.E[wall_axis]) { - 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.distance_scale_factor = glmth_max(0.0f, segment_scale_factor); - } + result.collision_occurred = true; + result.distance_scale_factor = glmth_max(0.0f, segment_scale_factor); } } } @@ -270,7 +276,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga if (player_is_in_tile && tile_id > 0) { color = (v3) {0.8f, 0.4f, 0.4f}; - assert(false); + //assert(false); } } @@ -407,6 +413,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga (i32)glmth_min(ROOM_TILE_DIM_Y, player_traversal_occupancy_bb.max.y + 2), }, }; + RENDER_COLLISION_DEBUG_QUAD(tile_search_range, ((v3) {0.8f, 0.8f, 0.8f})); f32 remaining_time_factor = 1.0f; @@ -443,14 +450,19 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga segment tile_l = {tile_sw, tile_nw}; segment tile_r = {tile_se, tile_ne}; - struct WallCollision bottom = get_wall_collision(player->pos, new_p, tile_b); + v2 norm_b = {0.0f, -1.0f}; + v2 norm_t = {0.0f, 1.0f}; + v2 norm_l = {-1.0f, 0.0f}; + v2 norm_r = {1.0f, 0.0f}; + + struct WallCollision bottom = get_wall_collision(player->pos, new_p, tile_b, norm_b); if (bottom.collision_occurred) { if (smallest_distance_scale_factor > bottom.distance_scale_factor) { smallest_distance_scale_factor = bottom.distance_scale_factor; } - wall_normal = (v2) {0.0f, -1.0f}; + wall_normal = norm_b; rect collision = { .min = tile_aabb.min, .max = {tile_aabb.max.x, tile_aabb.min.y + 0.2f}, @@ -458,14 +470,14 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga RENDER_COLLISION_DEBUG_QUAD(collision, ((v3) {1.0f, 0.0f, 0.0f})); } - struct WallCollision top = get_wall_collision(player->pos, new_p, tile_t); + struct WallCollision top = get_wall_collision(player->pos, new_p, tile_t, norm_t); if (top.collision_occurred) { if (smallest_distance_scale_factor > top.distance_scale_factor) { smallest_distance_scale_factor = top.distance_scale_factor; } - wall_normal = (v2) {0.0f, 1.0f}; + wall_normal = norm_t; rect collision = { .min = {tile_aabb.min.x, tile_aabb.max.y - 0.2f}, .max = tile_aabb.max, @@ -473,14 +485,14 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga RENDER_COLLISION_DEBUG_QUAD(collision, ((v3) {0.0f, 1.0f, 0.0f})); } - struct WallCollision left = get_wall_collision(player->pos, new_p, tile_l); + struct WallCollision left = get_wall_collision(player->pos, new_p, tile_l, norm_l); if (left.collision_occurred) { if (smallest_distance_scale_factor > left.distance_scale_factor) { smallest_distance_scale_factor = left.distance_scale_factor; } - wall_normal = (v2) {-1.0f, 0.0f}; + wall_normal = norm_l; rect collision = { .min = tile_aabb.min, .max = {tile_aabb.min.x + 0.2f, tile_aabb.max.y}, @@ -488,14 +500,14 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga RENDER_COLLISION_DEBUG_QUAD(collision, ((v3) {0.0f, 0.0f, 1.0f})); } - struct WallCollision right = get_wall_collision(player->pos, new_p, tile_r); + struct WallCollision right = get_wall_collision(player->pos, new_p, tile_r, norm_r); if (right.collision_occurred) { if (smallest_distance_scale_factor > right.distance_scale_factor) { smallest_distance_scale_factor = right.distance_scale_factor; } - wall_normal = (v2) {1.0f, 0.0f}; + wall_normal = norm_r; rect collision = { .min = {tile_aabb.max.x - 0.2f, tile_aabb.min.y}, .max = tile_aabb.max, @@ -535,9 +547,9 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga v2 colliding_velocity_component = glmth_v2f_m(wall_normal, glmth_v2_dot(player->velocity, wall_normal)); player->velocity = glmth_v2_s(player->velocity, colliding_velocity_component); + player_delta = glmth_v2f_m(player->velocity, dt); new_p = glmth_v2_a(player->pos, player_delta); - remaining_time_factor -= smallest_distance_scale_factor; } }