From 1961cd353b59b17d0903e56471d330ebf3851db3 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 1 Mar 2026 18:33:45 +0000 Subject: [PATCH] Fix on_ground flickering on one-way platform tiles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The platform collision check in resolve_tilemap_y required vel.y > 0 (strictly falling), so once landing zeroed vel.y the check would fail next frame. Gravity would add a tiny downward velocity, the platform would catch it again, and the cycle repeated — causing animation jitter and repeated landing dust particles. Change the condition to vel.y >= 0 so platforms resolve when resting. Extend the ground-stick anti-flicker probe to also detect TILE_PLATFORM tiles (was TILE_SOLID only), with a proximity guard to preserve jump-through-from-below behavior. --- src/engine/physics.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/engine/physics.c b/src/engine/physics.c index a230706..9c69c16 100644 --- a/src/engine/physics.c +++ b/src/engine/physics.c @@ -76,11 +76,14 @@ static void resolve_tilemap_y(Body *body, const Tilemap *map) { for (int tx = left; tx <= right; tx++) { uint32_t flags = tilemap_flags_at(map, tx, ty); if (!(flags & TILE_SOLID)) { - /* Check one-way platforms: only block when falling down */ - if ((flags & TILE_PLATFORM) && body->vel.y > 0) { + /* Check one-way platforms: block when falling or resting on top. + * vel.y >= 0 prevents on_ground flickering when standing still — + * gravity adds a tiny downward vel each frame, the platform + * resolves it back to zero, and the cycle would repeat. */ + if ((flags & TILE_PLATFORM) && body->vel.y >= 0) { float tile_top = tile_to_world(ty); float body_bottom = body->pos.y + body->size.y; - /* Only resolve if we just crossed into the tile */ + /* Only resolve if we just crossed into the tile or are resting on it */ if (body_bottom - body->vel.y * DT <= tile_top + 2.0f) { body->pos.y = tile_top - body->size.y; body->vel.y = 0; @@ -134,17 +137,31 @@ void physics_update(Body *body, float dt, const Tilemap *map) { /* Ground-stick probe: if not detected as on_ground but vel.y is * near zero (just landed or standing), check one pixel below. * Prevents flickering between grounded/airborne each frame due to - * sub-pixel gravity accumulation. */ + * sub-pixel gravity accumulation. Checks both solid tiles and + * one-way platforms. */ if (!body->on_ground && body->vel.y >= 0 && body->vel.y < s_gravity * dt * 2.0f && map) { int left = world_to_tile(body->pos.x); int right = world_to_tile(body->pos.x + body->size.x - 1); int probe = world_to_tile(body->pos.y + body->size.y + 1.0f); + float body_bottom = body->pos.y + body->size.y; for (int tx = left; tx <= right; tx++) { - if (tilemap_is_solid(map, tx, probe)) { + uint32_t pf = tilemap_flags_at(map, tx, probe); + if (pf & TILE_SOLID) { body->on_ground = true; body->vel.y = 0; break; } + /* One-way platforms: only stick if feet are at or above the + * platform top. Prevents snapping to a platform the player + * is below (e.g. jumping up through it). */ + if (pf & TILE_PLATFORM) { + float tile_top = tile_to_world(probe); + if (body_bottom <= tile_top + 2.0f) { + body->on_ground = true; + body->vel.y = 0; + break; + } + } } } }