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:
M | src/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;
}
}