On this page
- Why this article exists on a games site
- Rule 1: failure must be attributable
- Rule 2: the first thirty seconds teach
- Rule 3: budget spawns, do not scale them blindly
- Rule 4: telegraph everything that can kill
- Rule 5: give the player one thing to get better at
- Rule 6: instant restart, always
- Rule 7: test against numbers, not feelings
- Building the loop before the content
- Tuning numbers that actually matter
- Making a game readable
- Common failure modes and their symptoms
- Testing without a test team
- What belongs in a shared engine
Why this article exists on a games site
We build every game on Zombie Games Hub ourselves, and the rules below are the ones we actually apply. Publishing them serves two purposes: it explains why our games behave the way they do, and it is genuinely useful to anyone building something similar.
Nothing here is theoretical. Each rule exists because breaking it produced a game that playtested badly, and each is followed by the specific failure it prevents.
Rule 1: failure must be attributable
A player who dies should be able to name the mistake. Not necessarily immediately, but on reflection — 'I reloaded too late', 'I backed into a corner', 'I missed the runner'.
Deaths that cannot be attributed to a decision feel unfair regardless of how difficult the game actually is, and unattributable deaths are the primary reason players abandon arcade games. The usual causes are avoidable:
- Off-screen spawning near the player. Enemies must appear where the player can see them or from a clearly telegraphed edge.
- Random introduction of new enemy types. A brute in the first ten seconds teaches nothing.
- Instant-kill mechanics with no wind-up. Every lethal threat needs a readable tell.
- Invisible state. If a resource matters, it needs a visible meter.
If a playtester says 'that was unfair' more than once, the problem is almost never difficulty. It is attribution.
Rule 2: the first thirty seconds teach
The opening of an arcade game is not a difficulty setting, it is a tutorial that does not announce itself. A first-time player must survive long enough to learn the control scheme, the enemy appearance and the movement speeds.
Our target is that a complete beginner survives at least thirty seconds on their first attempt in every game. That is measurable and we test against it. Games that fail the test get a gentler opening spawn budget rather than a difficulty option, because a difficulty menu asks the player to make a decision before they have any basis for it.
Rule 3: budget spawns, do not scale them blindly
The naive approach to escalation is to multiply spawn rate by elapsed time. This produces runs that are boring at the start and impossible at the end.
A budget approach works better. Each wave or interval gets a point budget, enemies cost points by type, and the director spends the budget with constraints on how many can be alive at once. This gives you three useful levers independently: total pressure, composition and concurrency.
| Enemy | Cost | Role |
|---|---|---|
| Walker | 1 | Baseline pressure and crowd shape |
| Runner | 2 | Urgency; forces prioritisation |
| Crawler | 2 | Visual challenge; punishes tunnel vision |
| Brute | 5 | Resource drain; forces disengagement |
The concurrency cap matters more than the budget. A wave of thirty walkers arriving eight at a time is a fair challenge; the same thirty arriving at once is a screen-filling mess that cannot be played well by anyone.
Rule 4: telegraph everything that can kill
Every lethal or costly event needs a signal that precedes it by at least the player's response time — call it 400 ms as a working minimum, and more for anything requiring a decision rather than a reflex.
- Spawns: an edge indicator or a visible approach from off-field.
- Charges and lunges: a wind-up animation or colour change.
- Timers: a visible countdown, not a sudden expiry.
- Resource exhaustion: a warning state before the resource hits zero.
- Difficulty steps: an announcement, even if only a wave number changing.
Telegraphing does not make a game easier in any meaningful sense — a skilled player was going to react anyway. It makes the game learnable, which is what determines whether anyone stays long enough to become skilled.
Rule 5: give the player one thing to get better at
A game that tests aim, positioning, resource management and reaction simultaneously is not four times as deep. It is unreadable, because a player cannot tell which of the four caused any given failure and therefore cannot improve at any of them.
Every game on this site has a primary skill and at most one secondary. Zombie Target is aim and nothing else. Zombie Rush is movement and nothing else. Zombie Hunter is prioritisation with aim as the secondary. The flagship, Ultimate Zombie Arcade, is the deliberate exception — and it separates its skills into stages rather than mixing them.
Rule 6: instant restart, always
The gap between failing and playing again determines how many attempts a player makes, and the number of attempts determines whether they improve.
Our target is under one second from game-over to playable, achieved with a single click or the R key. No confirmation dialogs, no score submission step, no interstitial. The game-over screen shows the result and a Play Again button focused by default, so the keyboard path is Enter.
This is also an accessibility requirement, not just a retention one. A player using keyboard navigation should never have to tab through a screen to restart.
Rule 7: test against numbers, not feelings
Balance discussions collapse without measurements. The four numbers we test against for every game:
- First-attempt survival: at least 30 seconds for a complete beginner.
- Median run length: between one and four minutes after five attempts.
- Skilled run length: at least four times the first-attempt time — if it is not, skill is not expressing itself.
- Improvement visibility: a measurable gain within ten attempts.
That third number is the most diagnostic. If a very good player can only survive twice as long as a beginner, the difficulty curve is too steep or too linear, and no amount of content will make the game feel rewarding.
Building the loop before the content
The most common structural mistake in a first arcade game is building content before the loop is right — levels, enemies and art on top of a core that is not yet fun for thirty seconds.
A useful discipline: get one enemy type, one player action and one failure condition working, then play it for ten minutes. If ten minutes of one enemy type is boring, adding five more will not fix it, because the problem is in the verb rather than the variety.
- One verb. Shoot, dodge, jump, place. Pick one and make it feel good in isolation.
- One constraint. Ammunition, cooldown, space, time. Without a constraint the verb has no decisions attached.
- One failure condition. Clear and immediate.
- Then, and only then, variety. Enemy types, environments, escalation.
Every game on this site started as a prototype under a hundred lines that was playable before it was interesting. The ones that failed that ten-minute test were rebuilt around a different verb rather than padded with content.
Tuning numbers that actually matter
Balance discussions sprawl unless they are anchored to specific quantities. These are the ones that change how a game feels most.
| Quantity | Typical range | What it controls |
|---|---|---|
| Player speed vs. slowest enemy | 3–5× faster | Whether escape is always possible |
| Player speed vs. fastest enemy | 1.05–1.3× faster | Whether runners are a real threat |
| Time-to-kill, basic enemy | 1 hit | Whether crowds are clearable |
| Time-to-kill, heavy enemy | 4 hits | Whether kiting beats fighting |
| Reload / cooldown | 0.9–1.8 s | Whether timing is a decision |
| Difficulty half-life | 45–70 s | Where the ramp and plateau land |
| Contact damage | 10–20% of max health | How many mistakes a run can absorb |
The two speed ratios do most of the work. If the fastest enemy is slower than the player by a wide margin, nothing is ever urgent. If it is faster, the player has no agency. The narrow band just above parity is where chases become tense without becoming hopeless.
Making a game readable
Readability is the property that separates a hard game from a frustrating one, and it is mostly a visual-design problem rather than a balance problem.
- Silhouette before colour. Enemy types should be distinguishable by shape and size alone, so that colour is reinforcement rather than the only channel.
- Size encodes threat consistently. Across all thirty games here, smaller and lighter means faster; larger and darker means tougher. Consistency across a library is worth more than cleverness within one game.
- Player must always be findable. A distinct colour that nothing else uses. Losing track of your own character for even a moment is fatal and unfair.
- State changes need a visual and an audio channel. Reload, cooldown, damage, pickup. One channel is not enough for players who cannot use it.
- Keep the background quiet. Detailed backgrounds compete with gameplay elements for attention and the gameplay always loses.
A good readability test: take a screenshot mid-run and show it to someone who has never played. They should be able to point at the player, name the most dangerous thing on screen, and say what is about to happen.
Common failure modes and their symptoms
| Symptom in playtesting | Likely cause | Fix |
|---|---|---|
| 'That was unfair' | Attribution failure | Telegraph, or stop spawning off-screen |
| 'It got boring' | Curve too flat, or one dominant strategy | Introduce a threat that punishes the strategy |
| 'I don't know what to do' | Too many systems at once | Cut to one primary skill |
| 'It's too hard' | Usually the opening, not the whole game | Soften the first 30 seconds only |
| Everyone plays identically | One strategy dominates | Add a cost to it, not a nerf |
| Scores cluster tightly | Randomness dominates skill | Reduce variance, not difficulty |
The last row is subtle and important. If skilled and unskilled players score similarly, adding difficulty will not help — it will make everyone score less. The problem is that outcomes are not tracking decisions, which is a variance problem.
Testing without a test team
Most people building an arcade game are testing it alone, which introduces specific blind spots. Some workarounds that genuinely help.
- Automate a random-input run. A bot pressing keys at random should survive roughly ten to twenty seconds. Much less means the opening is too harsh; much more means it is too generous.
- Play with your non-dominant hand. A crude but effective proxy for a less skilled player, and it exposes control schemes that only work when you are precise.
- Leave it for a week. Returning without muscle memory reveals how the opening actually reads to a newcomer.
- Watch someone play once and say nothing. The urge to explain is exactly the signal that something is not readable.
- Log where runs end. A histogram of end times tells you where the curve is too steep far more reliably than memory does.
The first of those is what we use here. Every game in this library is run headlessly with synthetic input for thousands of frames before release — it catches crashes, and the survival time under random input is a genuinely useful tuning signal.
What belongs in a shared engine
If you are building more than one arcade game, the question of what to share becomes the main architectural decision. Share too little and every game reimplements the loop; share too much and the engine starts dictating what games can exist.
The line that worked for us: share anything that should behave identically, and nothing that expresses what a game is.
| Shared | Not shared |
|---|---|
| The frame loop and delta-time clamping | What update() does |
| Input abstraction (actions, not keys) | Which actions a game uses |
| State machine and overlay screens | Win and loss conditions |
| HUD rendering and field formatting | Which fields exist |
| Object pooling and collision maths | Entity behaviour |
| Particles, screen shake, audio | When they fire |
| Personal bests and play recording | What counts as a result |
| Canvas sprite drawing helpers | Scene composition |
| Difficulty curve functions | Which dial a game turns |
The right-hand column is what makes thirty games different from one game with thirty levels. Every item in it lives in the individual game file, which is why those files are a few hundred lines each rather than a few thousand.
The test we used: if adding a feature to the engine required a game to opt out of it, it did not belong in the engine. That rule killed several plausible-sounding shared systems — a universal enemy AI, a shared upgrade framework, a standard wave format — all of which would have made the games more similar to each other for no gain.
Key takeaways
- Every failure must be attributable to a decision the player can name.
- The first thirty seconds are a tutorial. Beginners must survive them.
- Budget spawns by enemy cost and cap concurrency — the cap matters more than the budget.
- Telegraph anything lethal by at least 400 ms; telegraphing makes games learnable, not easy.
- One primary skill per game, and a skilled run should be at least four times a first attempt.
- Get one verb, one constraint and one failure condition fun for ten minutes before adding content.
- The ratio between player speed and the fastest enemy does more for tension than any other number.
- Enemy types must be distinguishable by silhouette, with colour as reinforcement rather than the only channel.
- If skilled and unskilled players score similarly, the problem is variance rather than difficulty.
- Share what should behave identically; keep anything that expresses what a game is in the game file.