Crash-tan Crash-tan

CrashCore 1.22.1 is out!

Crash BASIC 1.22.1 Release Notes

written by Crash-tan

THE "DON'T SLIP PAST THE CORNER" FIX

Squash of a subtle collision bug that let sprites walk diagonally through solid boundaries when they were sliding along one face and crossed a corner. Plus the wall-stick regression the original attempt at this fix introduced.

The break point

The collision resolver runs steps in a specific order: inset edge-boxes for wall-face detection, cross-axis re-checks, and a full-rect dead-zone guard as backstop. Each of those steps uses a 2-pixel inset on the cross-axis of its test box. That inset exists to keep the sprite from snagging on tile seams while sliding along a wall — a feature, not a bug.

The problem: when a sprite slides along a wall's face (say, pressing LEFT against a right-side wall while moving UP), there's a 2-pixel "danger band" at the top of the wall where the sprite has 1 or 2 pixels of real overlap on the sliding axis. In that band, the inset trims the edge-box's range just far enough that it misses the wall. Step 1 thinks there's no collision. Step 2 thinks there's no collision. Step 4's dead-zone guard thinks there's no collision because at the new position the sprite's sliding-axis is now disjoint (it crossed the edge in one tick). The sprite slips LEFT past the wall's top-right corner diagonally, and once past, it can move freely through the wall's projection.

Symmetric bug in all four face-approach × corner directions: UP+LEFT along right face, UP+RIGHT along left face, DOWN+LEFT along top face, DOWN+RIGHT along bottom face (and the remaining four with mirrored signs).

The fix

A new post-step-4 guard in handle_entering_collision specifically for diagonal-past-corner slips:

if axis_A_entered_at_new
   AND axis_A_was_outside_at_old
   AND axis_B_had_real_overlap_at_old
   AND axis_B_exited_at_new
{
    block axis_A
}

Plain English: if the sprite's old position was sliding on one axis (real overlap on that axis, flush or disjoint on the other), and the movement took it out of that axis's overlap while entering the other axis, it's a diagonal corner slip — block the entering axis. The sprite keeps its legitimate sliding motion on the other axis but doesn't get to trade "past the corner" diagonally.

Runs symmetrically for both axes, so all four face-approach × eight movement-direction combinations are covered.

The wall-stick counter-fix

The first attempt at this fix blocked both axes on any diagonal into a flush-corner state. Fine in theory; awful in practice — every subsequent diagonal press against that corner produced zero movement. Pure 45° sliding felt glued.

Revised step 4 distinguishes two "sprite hit a corner" subcases:

  • Fresh diagonal entry (sprite had no contact with wall at old, 45° diagonal into corner): block both axes. Preserves the 1.19.4 anti-slip intent for first-frame approaches.
  • Flush-corner approach (sprite was already resting at exactly the wall's corner, then pressed diagonally): slide on one axis, never block both. No wall-stick.

Asymmetric diagonals (more X than Y or vice-versa) slide on the dominant axis in both cases — push the min-penetration axis back, let the dominant-penetration axis continue.

Tests

  • 16 new corner-point tests: 4 wall corners × 4 movement shapes (symmetric, X-dominant, Y-dominant, 8-px large). Each asserts the no-clip invariant (sprite's rect must not have real overlap on both axes of wall after correction) plus the no-stick invariant (sprite must be able to move at least one axis).
  • 4 diagonal-past-corner bypass tests, one per wall face × sliding direction, exercising the 1-2 px danger band specifically.
  • 2 multi-tick progression tests. The more punishing one holds UP+LEFT for 40 consecutive ticks starting flush against wall's right face and asserts on every frame that while the sprite still has Y overlap with the wall, its left edge never crosses into wall's x range. Catches cumulative drift that single-frame tests miss.
  • 3 existing tests updated to the tightened invariant (stricter than pre-1.22.1 — flush-corner 45° now slides instead of blocking both).

1167 crashcore tests green.

Why you care

If you've got a tile-based game with adjacent solid tiles forming walls (exactly the pattern the embedded test program uses), your player sprite can no longer walk diagonally through a wall by aligning with a corner and holding two movement keys.

And if you were noticing the sprite occasionally freezing against a wall when pressing diagonally, that's gone too. Slide means slide — whichever axis the player is pushing harder wins.