← All writing

/ 3 min read

Tuning fear by numbers

The player's kit never changes. Every bit of difficulty in I Won't Be Abducted lives in a Godot resource, and here is how that held up.

systems-design / godot / difficulty / data-driven

Most jam games escalate by addition. Night two adds an enemy, night three adds a weapon, and by the deadline you are debugging four mechanics instead of finishing one. For I Won’t Be Abducted I made the opposite bet before writing any code: the player’s kit stays constant for the whole game, and difficulty comes from the world.

The boy you control on the last night is the boy from night one. Move cooldown 0.18 seconds, kick cooldown 0.4 seconds, three Nerve hearts. The dawn draft lets you pick one upgrade between nights, but that is your choice, not the curve. The curve never touches your hands.

Systems map: the fixed player config, the per-night dials, and the event bus

Where the curve lives

Every gameplay number sits in a Godot Resource, a .tres file you edit in the inspector without opening a script. Four resource types drive the game: PlayerConfig, EnemyData, AugmentData, and the one doing the difficulty work, NightConfig:

  • duration (how long until dawn)
  • spawn_interval (seconds between alien drops)
  • max_on_board (population cap)
  • enemy_pool (which enemies can spawn, with per-enemy weights)
  • enemy_speed_scale (a multiplier on alien step timers)
  • intensity_ramp (how spawn pressure climbs within a night)
  • gift_interval / gift_amount (Scrap pickups)

Night one and night four are the same scene, the same code, the same rules. They differ in those numbers, in which enemies are in the pool, and since September in the size of the board. Rebalancing means opening a file and turning a dial: make night one gentler by raising the spawn interval and lowering the cap. In the last hours of a 63-hour jam that mattered more than any feature. Tuning time is the scarcest resource a jam has, and a curve made of inspector fields is the cheapest curve to iterate.

When a number can’t fix it, the rule is wrong

Twice during the jam no dial produced the right feel, and both times the fix was a rule change rather than a bigger number.

First: aliens only leave the board through real exits. The door and two windows are specific cells, not abstract directions. Players learned fast to hug corners, where a kick had no exit lane and did nothing. No dial fixes a wasted kick. A rule did: a kick that slams a chain of aliens into a wall now stuns the whole chain. Every kick does something. With kicks reliably useful, the population numbers came back down, night two from five aliens to four and night three from six to five.

Second: the Lobber’s ray-gun dealt direct Nerve damage at range, which on a fifteen-cell board read as unfair because there was nowhere honest to hide. Changing its damage just moved the unfairness around. The rule change: the first ray-gun hit stuns you, and only a hit while you are already stunned costs a heart. Same enemy, same range, but the threat is readable and the punishment takes two mistakes.

That became my working test for the whole project. Tune with numbers until the numbers stop helping, then change one rule, then go back to numbers.

What it bought after the jam

The September update was the real test of the approach. A fourth night, a bigger board, a new armoured alien, three craftable tools, and a boss with a seven-opening pattern all went in without touching the player’s kit. The new enemy is mostly a spawn weight in the night three and four pools plus one rule, a charged kick to launch him. The boss timings are inspector fields, so the “too easy, then unreadable” swing described in the follow-up postmortem was tuned in data, not rewritten in code.

The difficulty story also stays legible to the player, because nothing new is introduced mid-run. The game gets harder the way a board game gets harder when you add pieces: same rules, turned up.

Character standees from I Won't Be Abducted
← Back to writing