A game about digging holes taught me that most of my design ideas were invisible, and that I am
terrible at guessing whether a puzzle is solvable.
Chimp Dig is a terrain-carving puzzle. You scrape away at destructible ground and let gravity do the rest, routing a
curled-up chimp down to a nest. There is no character to steer. The only verb is dig, and the only thing
you control is where.
You cannot take a hole back
The first decision was the one everything else had to live with: no undo. Dirt you remove is gone, and if you have
removed the wrong dirt the level is unwinnable — possibly several digs before you notice.
That sounds hostile, and it would be in a game with long levels. The answer was to make restarting cheaper than
undoing: levels are short, restart is instant, and the state you are restarting from is exactly the state you
started with, every time. A puzzle you can rewind is a puzzle you solve by nudging. A puzzle you have to restart is
one you have to look at first. Digging only feels consequential if it is consequential.
The engine only really goes down
Here is the constraint that quietly ate half my ideas. At the gravity this game runs, the chimp barely rolls. Give
him a horizontal ledge to travel along and he stalls after about a hundred pixels, which is a third of the play
area's width.
I spent a while treating that as a bug to tune away. Cranking the gravity up made him roll further and also made
every landing feel like a dropped brick; adding roll made him skate past openings he should have dropped into. Both
fixes traded away the thing that made the game readable, which is that a gap directly below something means that
something is about to be directly below.
So I stopped fighting it. The levels are 360 pixels wide and as tall as they need to be, the camera only ever scrolls
up and down, and every route is predominantly vertical. Lateral movement is a garnish — a short slide off a
wedge into the next shaft — never a leg of the journey. Once I accepted that, levels started working on the
first try instead of the fifth.
I threw away a third of the materials
I started with a respectable list of terrain types, including root, clay and a leaf litter. Each had its own friction
and its own dig cost. All three are gone.
The reason is the vertical constraint again. In a game where nothing travels sideways for long, friction has almost
nothing to act on — you cannot feel the difference between sliding across clay and sliding across dirt when
the slide is forty pixels long. Dig cost fared no better: there is a budget in the engine, it is still there, it is
still tested, and I do not think a single level in the shipped set is meaningfully constrained by it. Three
materials that differed only in numbers the player could not perceive were three materials that did not exist.
What survived is six things that each do something visibly different. Air and dirt — dirt being the
only thing you can actually remove. Rock, which you cannot. Honey, which lets you through but slows you down. Web,
which catches the chimp and holds him, but tears under a falling coconut. And hazard, which ends the run.
The rule I ended up with, and would apply again: separate materials by what they do, not by what they feel like. Feel
needs a lot of screen time to register. Behaviour registers the first time you touch it.
Two ways a coconut ruins everything
Coconuts are the second moving object, and both of their failure modes were the physical-comedy kind — obvious
in hindsight, invisible on paper.
The first: if your dig radius is not comfortably larger than a coconut, the coconut wedges in the shaft it just fell
through. It arrives at a hole exactly its own size and stops, which is correct physics and useless gameplay. The dig
radius is now larger than the coconut, permanently, as a rule rather than a tuning value.
The second took longer to see. A coconut needs somewhere to end up that is not where the chimp needs to go. Share a
narrow channel between them and the coconut plugs it, sitting in the one gap the chimp was supposed to fall through.
Every level with a coconut now has a place for it to come to rest clear of the route — a side pocket, a ledge,
a dead end. Designing the coconut's retirement home turned out to be as much work as designing its job.
Blocking works on a floor, never in a pinch
A subtler one. I assumed you could stop the chimp by pinching him — leaving a gap narrower than he is and
letting the walls catch him. It does not work, and the reason is in how contact is resolved: the probe averages
everything touching him into a single surface normal. Two walls squeezing from opposite sides average out to roughly
nothing, so he slides straight down between them as though they were not there.
Resting on a floor works, because a floor is one normal pointing one way. So every deliberate stopping point in every
level is something underneath him, never something either side of him. That is not a limitation I would have written
down in advance, and it invalidated a handful of half-built levels the day I found it.
I stopped guessing whether levels were solvable
For the first stretch I authored levels by eye: carve a shape, imagine the route, playtest it. My hit rate was poor.
Not "needs tuning" poor — routinely, flatly unsolvable, or solvable by a route so much easier than the
intended one that the puzzle evaporated.
So there is a route searcher. It takes a level and explores parameterised dig paths, hunting for a sequence that gets
the chimp home. Every level from one called thorn-gap onwards was authored with it in the loop: shape the terrain,
run the search, look at what it found. Sometimes it finds nothing and the level needs another opening. More often it
finds something I did not intend, which is the more useful answer, because that is the route players will find too.
It works at all because of a decision made much earlier: the core is headless and deterministic, and a run is a pure
function of a level plus an ordered list of dig events. No rendering, no clock, no randomness. That is what lets a
search play thousands of candidate solutions in the time it takes to make a cup of tea, and it is the single thing I
would keep if I had to throw the rest away.
Two file formats that saved me later
Both of these looked like fussy over-thinking at the time and both paid for themselves.
The editor saves terrain as characters, not material ids. When I retired root, clay and leaf, every material id after
them shifted — and every level file that had stored raw ids would have quietly become a different level.
Storing an r instead of a 4 meant the great material cull cost me nothing but a
find-and-replace.
The playtest exports a replay rather than a path. It records the tick each dig happened on, not just the order. That
matters because the hazards move on their own schedule, so "dig here, then here" is not enough information to
reproduce a run — the same two digs a hundred ticks apart are two different outcomes. A list of places is a
guess. A list of moments is a recording.
Where it stands
Twenty-four levels, ordered by their own ids rather than by position, so that inserting one in the middle does not
wipe anyone's progress. The editor and the level selector exist but are lazily loaded behind a development flag, so
the module is never fetched in a normal build — the tools are in the repository, not in your download.
The vestigial dig budget is still sitting there, tested and unused. I keep meaning to delete it, and I keep not
deleting it, on the theory that a level built around running out of digs is a good idea I have not had yet.