commit 68087cc3b1f2e69edbdc710a02f6248d2530c45b
parent 704f18b717c404b6a6cd96ec2290534990236aa1
Author: amin <dev@aminmesbah.com>
Date: Wed, 24 Apr 2019 06:16:51 +0000
Fix tunneling bug by expanding search range
Here's what appears to have happened: the tile search range around the
player's movement path was too small at low velocities. This resulted in
the player occasionally tunneling through a solid tile not included in
the search range, and therefore not collision tested against.
FossilOrigin-Name: 729eafb439c4f0535e174ec9290eaa8a3d89830c77f73697a17f16feb7d930bd
Diffstat:
M | src/game.c | | | 76 | ++++++++++++++++++++++++++++++++++------------------------------------------ |
1 file changed, 34 insertions(+), 42 deletions(-)
diff --git a/src/game.c b/src/game.c
@@ -14,11 +14,8 @@ internal void game_init(struct GameMemory *game_memory, v2u framebuffer)
struct GameState *game_state = game_memory->game_state;
// init player
- //game_state->player.pos = (v2) {12.5f, 5.0f};
- game_state->player.pos = (v2) {10.812491f, 3.752474f};
- game_state->player.velocity = (v2) {0.0f, 5.0f};
- game_state->player.pos = (v2) {10.736823f, 3.591690f};
- game_state->player.velocity = (v2) {5.0f, 5.0f};
+ game_state->player.pos = (v2) {12.5f, 5.0f};
+
// 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
game_state->player.dimensions = (v2) {0.375f, 0.583f};
@@ -272,8 +269,6 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
{
color = (v3) {0.8f, 0.4f, 0.4f};
printf("!!!!!!!!!!!!!!!!\n");
- glmth_print(glmth_v2_a(player.pos, glmth_v2f_m(player.dimensions, 0.5f)));
- glmth_print(player.velocity);
assert(false);
}
}
@@ -295,8 +290,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
f32 dt = game_input->dt;
f32 max_meters_per_second = 5.0f;
f32 acceleration_rate = 50.0f;
- //f32 friction = 0.7f;
- f32 friction = 1.0f;
+ f32 friction = 0.7f;
if (game_input->key_up)
{
@@ -381,13 +375,12 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
#else
{
#define RENDER_COLLISION_DEBUG_QUAD(r, c) render_debug_quad(game_state, (r), (c), &view, &projection);
- printf("--------------\n");
- v2 old_p = player->pos;
- v2 new_p = glmth_v2_a(old_p, glmth_v2f_m(player->velocity, dt));
+ v2 player_delta = glmth_v2f_m(player->velocity, dt);
+ v2 new_p = glmth_v2_a(player->pos, player_delta);
rect player_traversal_bb = {
- .min = {glmth_min(old_p.x, new_p.x), glmth_min(old_p.y, new_p.y)},
- .max = {glmth_max(old_p.x, new_p.x), glmth_max(old_p.y, new_p.y)},
+ .min = {glmth_min(player->pos.x, new_p.x), glmth_min(player->pos.y, new_p.y)},
+ .max = {glmth_max(player->pos.x, new_p.x), glmth_max(player->pos.y, new_p.y)},
};
//RENDER_COLLISION_DEBUG_QUAD(player_traversal_bb, ((v3) {0.4f, 0.4f, 0.4f}));
@@ -396,24 +389,19 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
rect tile_search_range = {
.min = {
- (i32)glmth_max(0.0f, player_traversal_occupancy_bb.min.x),
- (i32)glmth_max(0.0f, player_traversal_occupancy_bb.min.y),
+ (i32)glmth_max(0.0f, player_traversal_occupancy_bb.min.x - 1),
+ (i32)glmth_max(0.0f, player_traversal_occupancy_bb.min.y - 1),
},
.max = {
- (i32)glmth_min(ROOM_TILE_DIM_X, player_traversal_occupancy_bb.max.x + 1),
- (i32)glmth_min(ROOM_TILE_DIM_Y, player_traversal_occupancy_bb.max.y + 1),
+ (i32)glmth_min(ROOM_TILE_DIM_X, player_traversal_occupancy_bb.max.x + 2),
+ (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}));
- v2 player_delta = glmth_v2_s(new_p, old_p);
f32 remaining_time_factor = 1.0f;
for (u32 i = 0; i < 4 && remaining_time_factor > 0.0f; i++)
{
- printf("Iteration %u:\n", i);
- old_p = player->pos;
- new_p = glmth_v2_a(old_p, glmth_v2f_m(player->velocity, dt));
- player_delta = glmth_v2_s(new_p, old_p);
v2 wall_normal = {0};
f32 smallest_distance_scale_factor = 1.0f;
for (i32 tile_y = tile_search_range.min.y; tile_y < tile_search_range.max.y; tile_y++)
@@ -446,8 +434,7 @@ 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(old_p, new_p, tile_b);
+ struct WallCollision bottom = get_wall_collision(player->pos, new_p, tile_b);
if (bottom.collision_occurred)
{
if (smallest_distance_scale_factor > bottom.distance_scale_factor)
@@ -462,7 +449,7 @@ 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(old_p, new_p, tile_t);
+ struct WallCollision top = get_wall_collision(player->pos, new_p, tile_t);
if (top.collision_occurred)
{
if (smallest_distance_scale_factor > top.distance_scale_factor)
@@ -477,7 +464,7 @@ 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(old_p, new_p, tile_l);
+ struct WallCollision left = get_wall_collision(player->pos, new_p, tile_l);
if (left.collision_occurred)
{
if (smallest_distance_scale_factor > left.distance_scale_factor)
@@ -492,7 +479,7 @@ 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(old_p, new_p, tile_r);
+ struct WallCollision right = get_wall_collision(player->pos, new_p, tile_r);
if (right.collision_occurred)
{
if (smallest_distance_scale_factor > right.distance_scale_factor)
@@ -509,21 +496,26 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
}
}
}
- v2 nearest_collision_p = glmth_v2_a(old_p, glmth_v2f_m(player_delta, smallest_distance_scale_factor));
+
+ v2 delta_to_nearest_collision = glmth_v2f_m(player_delta, smallest_distance_scale_factor);
+ v2 nearest_collision_p = glmth_v2_a(player->pos, delta_to_nearest_collision);
+
player->pos = nearest_collision_p;
- player->velocity = glmth_v2_s(
- player->velocity,
- glmth_v2f_m(wall_normal, glmth_v2_dot(player->velocity, wall_normal))
- );
- player_delta = glmth_v2_s(
- player_delta,
- glmth_v2f_m(player_delta, glmth_v2_dot(player->velocity, wall_normal))
- );
- remaining_time_factor -= smallest_distance_scale_factor * remaining_time_factor;
- glmth_print(player_delta);
- glmth_print(glmth_v2_a(player->pos, glmth_v2f_m(player->dimensions, 0.5f)));
- glmth_print(player->velocity);
- printf("time remaining: %f\n", remaining_time_factor);
+
+ // NOTE(amin):
+ // n * dot(v, n)
+ // = n * (|v| * |n| * cos(theta))
+ // = n * (|v| * 1 * cos(theta))
+ // = n * (|v| * cos(theta))
+ // = n * |v_projected_onto_n|
+ // = v_projected_onto_n
+ 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;
}
}
#undef RENDER_COLLISION_DEBUG_QUAD