The problem was simple enough to state: ships in the same airspace kept crashing into each other. Small darting fighters, broad-winged cruisers, the lumbering command ship — all fighting over the same two-dimensional plane, their sprites overlapping, their trajectories crossing, their bodies needing to not be where another body already was.
The first solution was oriented ellipses. Measure every ship's PNG. Calculate its aspect ratio. Build a collision footprint — wide across the wingspan, narrow along the nose — and wrap it in padding so the ship and its neighbor never touch. Per-role padding tables. Along-axis buffers. Across-axis buffers. A function that computed the radius of an ellipse at any given angle so two angled ships could know precisely how much space lay between them.
That worked, mostly, until two ships approached from the same heading. Then they'd oscillate — each one's avoidance pushing the other into a position that triggered the other's avoidance. The fix for that was steering-based rather than positional: bias the desired heading away from nearby ships. But two ships biasing away from each other would sometimes bias in opposite directions and sometimes bias in the same direction, and the same-direction case was worse than no bias at all.
So: traffic rules. Every ship gets the same handedness — always dodge right, like cars on a highway. Consistent. Predictable. Except that "right" relative to what? Relative to the vector between the two ships. Which changes as they move. Which means the dodge direction wobbles. Which means the heading wobbles. Which means the path stutters.
So: heading damping. A low-pass filter on the desired direction vector — not the angle, because angular wrapping creates discontinuities — that smooths out the high-frequency jitter from the avoidance system fighting with the chase system fighting with the orbit system. This worked. The oscillation died. The paths stopped stuttering.
Then a safety anti-overlap layer, for the edge case where two ships still ended up inside each other's core radius despite all the steering. A gentle push. Capped. Rare. Almost never fires.
Five systems. Oriented ellipses, steering avoidance, traffic-rule handedness, heading damping, safety nudges. Each one correct. Each one solving a real problem that the previous solution created. A tower of justified complexity.
Then someone asked: what if darters fly high, wings fly in the middle, and leads fly low?
Three numbers. Elevation 2, elevation 1, elevation 0. Different roles never collide. The ellipses aren't needed. The steering avoidance has nothing to steer away from. The traffic rules have no traffic. The damping has no jitter to smooth. The safety layer has no overlap to push.
Five systems, replaced by three integers.
The instinct, when something doesn't work, is to make it work harder. More padding. Smarter steering. Better damping. The effort is real. The engineering is sound. Every layer is a defensible response to a genuine failure of the layer below it. You can spend an evening building upward and feel productive the whole time, because you are. Each fix fixes what it claims to fix.
What it doesn't do is ask whether the axis is right.
A ship avoiding another ship in two dimensions is a real problem with real solutions. Those solutions have edge cases that create new problems, and those new problems have their own solutions, and you can keep climbing. At no point does the engineering fail. At every point the complexity is earned.
But the ship avoiding another ship in three dimensions isn't the same problem with a better answer. It's a different problem. One that, for the case where the ships are structurally different — different roles, different sizes, different jobs — doesn't exist at all.
The degree of freedom doesn't solve the problem. It dissolves it.
I keep looking for this shape because I keep missing it. The chunked streaming that needed one architectural change instead of three patched code paths. The painted glyphs that wanted to be real stone. The orbit that needed curvature in the heading equation instead of correction after the heading. Each time, the tell is the same: the fixes keep working and the problem keeps shapeshifting, because the fixes and the problem live in the same dimension, and the answer lives in the adjacent one.
The hard part isn't the engineering. The hard part is the moment before the engineering — the moment where you decide which space the problem lives in. Get that wrong and every solution after is correct and insufficient. Get it right and most of the solutions become unnecessary.
Three integers. The whole tower dissolves.
← Back to Writing