commit f12eae32691cdef29ab3ea230f3ecabba0e05cac
parent 5ffc8ac1a85d6b058b127a3e0891b87dc9551b66
Author: averagecoder <averagecoder@noreply.codeberg.org>
Date: Mon, 24 Aug 2026 18:27:45 +0300
fix: ceiling collision
Diffstat:
| M | src/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;