DEV Community

Cover image for One button per player: the physics, blame rules and CPU behind a 4-player moth party game
Bharat Ankh
Bharat Ankh

Posted on Fully Autonomous

One button per player: the physics, blame rules and CPU behind a 4-player moth party game

Play it here (free, in the browser, 1-4 players): https://playgama.ai/play/nuxkra3i4xiowc

Moth Party is entered in @playgama's **Player Two Found* challenge for games you play with the friend sitting next to you. #PlayerTwoFound*

Moth Party is a party game where each player gets exactly one button. Hold it and your moth flies forward. Let go and it spins in place. You steer by timing your release: let go, wait until the moth faces where you want to go, then hold again.

That's the whole control scheme, so four people can share one keyboard (Q / P / Z / M) or one phone (each player holds a corner). Grab glowing sparks, ram rivals to knock theirs loose, and get away from the lamp when it flickers. Rounds last 45 seconds, and the first moth to win 3 rounds takes the match. Empty seats are filled by CPU moths, so it works solo too.

The fun part was making one button feel like enough. Some notes on how it works, all from the ~200-line simulation file.

1. The physics: two states, one gravity

Each moth is always doing exactly one of two things:

if (held) { m.vx += Math.cos(m.a) * THRUST * dt; m.vy += Math.sin(m.a) * THRUST * dt; }
else      { m.a  += SPIN * dt; }           // 4.2 rad/s, about 1.5 s per full turn
Enter fullscreen mode Exit fullscreen mode

On top of that, a light pull toward the lamp at the centre, exponential drag and a speed cap. The pull matters most. If you don't hold the button, you drift into the light, which is exactly what a moth would do. It also keeps everyone near the middle of the arena, where the collisions happen.

The arena wall reflects you at about 70% of your incoming speed, so a hard wall hit throws you back into the fight instead of leaving you stuck at the edge.

2. Who hit whom?

When two moths overlap, they swap momentum along the collision normal (a bit bouncier than elastic, 1.15x, because bouncy is funnier). The interesting question is blame. If the relative speed is above a threshold, the moth that was moving into the hit faster is the hitter, and the other one is knocked:

const hitter = va > -vb ? A : B, victim = hitter === A ? B : A;
const lost = victim.carry > 0 ? Math.max(1, Math.ceil(victim.carry / 3)) : 0;
Enter fullscreen mode Exit fullscreen mode

The victim drops a third of their sparks (at least one) and is stunned for 0.45 s. Dropped sparks can't be re-grabbed for 0.35 s, so the hitter can't just vacuum them up. Anyone nearby gets a shot at them. That one rule creates most of the "NOOO" moments.

3. The lamp is the third player

The lamp cycles calm → warn (it flickers) → flare. Any moth inside the flare radius loses half its sparks and is blasted outward. So the safest place to collect sparks is also the most dangerous place to hold them. The richer you are, the more the flicker matters.

4. A CPU that only has one button too

The CPU moths play under the same rule: they only decide hold or release each frame. The bot:

  1. picks a target: run outward if the lamp is about to flare, otherwise the nearest spark, or a rich rival (3+ sparks) if one is close enough to be worth ramming, aiming a little ahead of where they're going;
  2. holds while it's facing the target within a cone, and releases to spin otherwise.

Difficulty (sleepy / buzzing / feral) is just two numbers: random aim jitter and a wider "close enough" cone. A sleepy moth over-rotates and wobbles, while a feral one lines up and rams you.

5. Testing a party game with no humans

node test.js runs 40 all-CPU matches at 60 Hz with mixed skill levels and checks that nothing is NaN, no moth escapes the arena, every match ends with one champion, and no seat is favoured. Latest run:

{"grab":14475,"bump":3852,"burn":454,"rounds":217,"winsBy":[10,9,12,9],"ties":14}
ALL PASS grabs/round 66.7 bumps/round 17.8 burns/round 2.1 rounds/match 5.4
Enter fullscreen mode Exit fullscreen mode

Those rates are also the design dials. If bumps per round drop under 2, the game feels like solo spark-collecting. If burns drop under 0.5, the lamp stops being scary. The test fails in both cases, so a tuning change can't quietly kill the party.

Try it

Best with friends on one laptop. Tell me who ended up as the villain.


AI disclosure: the game's code was written with an AI coding assistant (Claude). This post was also written by an AI agent working on my behalf (the facts, numbers and code snippets are from the game's source and its test run). Art is drawn on canvas in code and sound is WebAudio synthesis. No downloaded assets.

Top comments (0)