antizona

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit f12eae32691cdef29ab3ea230f3ecabba0e05cac
parent 5ffc8ac1a85d6b058b127a3e0891b87dc9551b66
Author: averagecoder <averagecoder@noreply.codeberg.org>
Date:   Mon, 24 Aug 2026 18:27:45 +0300

fix: ceiling collision

Diffstat:
Msrc/render.c | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 110 insertions(+), 52 deletions(-)

diff --git a/src/render.c b/src/render.c @@ -1233,9 +1233,9 @@ get_ground_height(float px, float pz, float cur_y) { const struct col_cell *c; const struct col_triangle *t; - float best_below, hit_y; + float best_below, hit_y, min_x, max_x, min_z, max_z; uint32_t i; - int gx, gz, cx_idx, cz_idx; + int gx, gz; gx = (int)((px - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ)); gz = (int)((pz - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ)); @@ -1244,45 +1244,92 @@ get_ground_height(float px, float pz, float cur_y) } best_below = -1000.0f; + c = &g_col_grid[gx][gz]; - for (cz_idx = gz - 1; cz_idx <= gz + 1; cz_idx++) { - if (cz_idx < 0 || cz_idx >= GRID_SZ) { + for (i = 0; i < c->count; i++) { + t = &c->tris[i]; + if (t->norm[1] < 0.45f) { continue; } - for (cx_idx = gx - 1; cx_idx <= gx + 1; cx_idx++) { - if (cx_idx < 0 || cx_idx >= GRID_SZ) { - continue; - } - c = &g_col_grid[cx_idx][cz_idx]; - for (i = 0; i < c->count; i++) { - t = &c->tris[i]; - if (t->norm[1] < 0.45f) { - continue; - } - if (ray_tri_intersect_y(t, px, pz, &hit_y)) { - if (hit_y <= cur_y + 0.50f && hit_y > best_below) { - best_below = hit_y; - } - } + + min_x = fminf(t->v0[0], fminf(t->v1[0], t->v2[0])); + max_x = fmaxf(t->v0[0], fmaxf(t->v1[0], t->v2[0])); + if (px < min_x || px > max_x) { + continue; + } + + min_z = fminf(t->v0[2], fminf(t->v1[2], t->v2[2])); + max_z = fmaxf(t->v0[2], fmaxf(t->v1[2], t->v2[2])); + if (pz < min_z || pz > max_z) { + continue; + } + + if (ray_tri_intersect_y(t, px, pz, &hit_y)) { + if (hit_y <= cur_y + 0.50f && hit_y > best_below) { + best_below = hit_y; } } } return (best_below); } +static float +get_ceiling_height(float px, float pz, float cur_y) +{ + const struct col_cell *c; + const struct col_triangle *t; + float best_above, hit_y, min_x, max_x, min_z, max_z; + uint32_t i; + int gx, gz; + + gx = (int)((px - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ)); + gz = (int)((pz - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ)); + if (gx < 0 || gx >= GRID_SZ || gz < 0 || gz >= GRID_SZ) { + return (1000.0f); + } + + best_above = 1000.0f; + c = &g_col_grid[gx][gz]; + + for (i = 0; i < c->count; i++) { + t = &c->tris[i]; + if (t->norm[1] > -0.2f && t->norm[1] < 0.2f) { + continue; + } + + min_x = fminf(t->v0[0], fminf(t->v1[0], t->v2[0])); + max_x = fmaxf(t->v0[0], fmaxf(t->v1[0], t->v2[0])); + if (px < min_x || px > max_x) { + continue; + } + + min_z = fminf(t->v0[2], fminf(t->v1[2], t->v2[2])); + max_z = fmaxf(t->v0[2], fmaxf(t->v1[2], t->v2[2])); + if (pz < min_z || pz > max_z) { + continue; + } + + if (ray_tri_intersect_y(t, px, pz, &hit_y)) { + if (hit_y >= cur_y + 1.0f && hit_y < best_above) { + best_above = hit_y; + } + } + } + return (best_above); +} + static void -move_and_slide(float *px, float *py, float *pz, float vx, float vz, float dt) +move_and_slide(float *px, float py, float *pz, float vx, float vz, float dt) { const struct col_cell *c; const struct col_triangle *t; float sphere[3][3]; float closest[3], diff[3], push_dir[3]; float rad, dist_sq, dist, push, h_len, dot, step_x, step_z; - float step_h, ground_y; - int sub, iter, s, i, gx, gz, cx_idx, cz_idx; + float min_x, max_x, min_z, max_z; + int sub, iter, s, i, gx, gz, gx0, gx1, gz0, gz1; rad = 0.35f; - step_h = 0.5f; for (sub = 0; sub < 2; sub++) { step_x = (vx * dt) * 0.5f; @@ -1291,34 +1338,32 @@ move_and_slide(float *px, float *py, float *pz, float vx, float vz, float dt) *px += step_x; *pz += step_z; - gx = (int)((*px - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ)); - gz = (int)((*pz - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ)); - if (gx < 0 || gx >= GRID_SZ || gz < 0 || gz >= GRID_SZ) { - continue; - } + gx0 = (int)((*px - rad - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ)); + gx1 = (int)((*px + rad - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ)); + gz0 = (int)((*pz - rad - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ)); + gz1 = (int)((*pz + rad - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ)); + + if (gx0 < 0) gx0 = 0; + if (gx1 >= GRID_SZ) gx1 = GRID_SZ - 1; + if (gz0 < 0) gz0 = 0; + if (gz1 >= GRID_SZ) gz1 = GRID_SZ - 1; - for (iter = 0; iter < 3; iter++) { + for (iter = 0; iter < 2; iter++) { sphere[0][0] = *px; - sphere[0][1] = *py + step_h + 0.15f; + sphere[0][1] = py + 0.35f; sphere[0][2] = *pz; sphere[1][0] = *px; - sphere[1][1] = *py + step_h + 0.75f; + sphere[1][1] = py + 0.95f; sphere[1][2] = *pz; sphere[2][0] = *px; - sphere[2][1] = *py + step_h + 1.35f; + sphere[2][1] = py + 1.55f; sphere[2][2] = *pz; - for (cz_idx = gz - 1; cz_idx <= gz + 1; cz_idx++) { - if (cz_idx < 0 || cz_idx >= GRID_SZ) { - continue; - } - for (cx_idx = gx - 1; cx_idx <= gx + 1; cx_idx++) { - if (cx_idx < 0 || cx_idx >= GRID_SZ) { - continue; - } - c = &g_col_grid[cx_idx][cz_idx]; + for (gz = gz0; gz <= gz1; gz++) { + for (gx = gx0; gx <= gx1; gx++) { + c = &g_col_grid[gx][gz]; for (i = 0; i < (int)c->count; i++) { t = &c->tris[i]; @@ -1326,6 +1371,18 @@ move_and_slide(float *px, float *py, float *pz, float vx, float vz, float dt) continue; } + min_x = fminf(t->v0[0], fminf(t->v1[0], t->v2[0])); + max_x = fmaxf(t->v0[0], fmaxf(t->v1[0], t->v2[0])); + if (*px + rad < min_x || *px - rad > max_x) { + continue; + } + + min_z = fminf(t->v0[2], fminf(t->v1[2], t->v2[2])); + max_z = fmaxf(t->v0[2], fmaxf(t->v1[2], t->v2[2])); + if (*pz + rad < min_z || *pz - rad > max_z) { + continue; + } + for (s = 0; s < 3; s++) { closest_point_triangle(sphere[s], t->v0, t->v1, t->v2, closest); @@ -1382,15 +1439,6 @@ move_and_slide(float *px, float *py, float *pz, float vx, float vz, float dt) } } } - - ground_y = get_ground_height(*px, *pz, *py); - if (ground_y > -900.0f) { - if (ground_y <= *py + step_h) { - if (ground_y > *py) { - *py = ground_y; - } - } - } } } @@ -2921,7 +2969,7 @@ main(int argc, char *argv[]) move_z /= move_len; player_yaw = atan2f(move_x, move_z); speed = 6.0f; - move_and_slide(&player_x, &player_y, &player_z, + move_and_slide(&player_x, player_y, &player_z, move_x * speed, move_z * speed, dt); } @@ -2947,7 +2995,17 @@ main(int argc, char *argv[]) player_vy = -TERMINAL_VEL; } - player_y += player_vy * dt; + if (player_vy > 0.0f) { + float ceil_y = get_ceiling_height(player_x, player_z, player_y); + if (ceil_y < 900.0f && (player_y + 1.85f + player_vy * dt) >= ceil_y) { + player_y = ceil_y - 1.85f; + player_vy = 0.0f; + } else { + player_y += player_vy * dt; + } + } else { + player_y += player_vy * dt; + } if (player_vy <= 0.0f && ground_y > -900.0f && player_y <= ground_y) { player_y = ground_y;