The Protagonist Was the Hot Path

Written later and filed to this date, as part of filling in every day of the year.

The player in my survivor shooter used to be a swarm. Not a ship with a particle trail: the swarm was the whole character, twenty glowing dots at level one growing by four a level to a hundred, held together by boids physics. Separation, cohesion, alignment, a pull toward the centre, a wander term, and a streaming force that compressed the leading particles into a bright teardrop whenever you moved. The repository’s own description said it in capitals: the player character IS the particle swarm. There was no sprite.

On a Thursday morning in April a commit with the subject performance changed that sentence to “the player character is a procedurally-drawn neon spaceship.” Thirty-three files, 4,112 lines added. I expected a performance commit to be invisible. This one changed the thing you look at for the entire run.

What was expensive

Read the diff and the word was accurate. A hundred particles, each one a display object of its own, each one running six forces every frame, three of them against its neighbours, plus the pass that kept the leaders bright and the trailers dim. In a late wave, with the screen full of enemies and every weapon firing, the thing the camera followed was also the most expensive object in the scene. The swarm was beautiful and it was the hot path, and those are not two facts about it. They are one fact.

The commit knew it, and did the obvious thing first. The swarm’s own file was rewritten so that all hundred particles drew into a single graphics object: one batch per frame instead of a hundred game objects, a comment on the new field says as much. That is the optimization a performance commit is supposed to contain, and it is in there, finished.

Then, in the same diff, the scene stopped constructing a swarm at all. A new file of 1,019 lines draws a hull from a handful of vertices, a delta nose, wing roots, wing tips, a tail notch, and rotates it toward the movement direction. Thrust flames scale with speed. The hull colour follows the combo tier, the four names warm, hot, blazing and inferno, and goes red at low health. It evolves through five tiers as you level, Scout to Fighter to Striker to Warbird to Apex, with a flash and a shape swap at each step. It costs a few polygons and a glow pass.

After the commit, nothing in the source imported the swarm. The optimized version sat in the tree, batched, unplugged.

Why both

I have thought about why the batching survived into the diff when the thing it batched did not, and the answer I believe is the order the work happened in. You optimize the swarm because the swarm is what you have. Partway through, with the numbers in front of you, you learn how much of the frame the character costs even batched, and the question changes from how to draw a hundred dots cheaply to whether the character needs to be a hundred dots. The ship is the answer to the second question. The batching is the fossil of the first.

The rest of the day confirms what the morning decided. By ten past three the ship file had been rewritten again, 1,033 lines changed, under the subject polish. That afternoon a one-line commit, Create CNAME, arrived from the hosting side. At twenty to seven a second performance commit changed the spatial hash to numeric cell keys so that lookups stopped allocating strings, and pulled out the screen-edge glow that had been redrawing on every combo tier change. At five to eight a third one. Four commits about speed in nine hours, and one of them is the one a player would describe as “the game looks different.”

Where the expectation came from

A performance commit should leave the game looking the same. I believed that, and the belief has a source: in most code the hot path is plumbing. You batch the draw calls, you pool the projectiles, you stop allocating in the loop, and the picture on screen is identical because the picture was never the cost. In this game the picture was the cost. The player is on screen every frame of every run, so whatever the player is made of is paid for more often than anything else, and a design decision about what the hero looks like had been a performance decision the whole time without anyone filing it as one.

The ship is a better character. It reads at a glance on a small screen, it shows its tier, it points where you are going. I would not have arrived at it by asking what the hero should look like. I arrived at it by asking what the frame could afford, and the swarm’s answer was no.


← all writing