Skip to content

Repository files navigation

AstroSwarm

Godot Language Platform Video Export Status Version

AstroSwarm is a 2D pixel-art tower-defense game (in development) built in Godot 4. It also includes a full swarm-behavior simulator sandbox: design species, program their behavior with a drag-and-drop block editor, then record, replay, and export sessions to video. The pixel-art game shell is themed separately from the simulator.

Features

  • Player base & progression. A procedurally generated home planet, moons that orbit it and unlock as you level up, an XP bar, and AstroCoin currency — all saved to a local profile.
  • Timed Local battles. Deploy a squad from your base to destroy the swarm guarding a central star, then program your ship's flight logic in the Hivemind moon's block editor.
  • Benchmarked levels. Eight FARP levels: program the defenders for levels 1 to 5 and have your algorithm graded headlessly by the evaluation service, steer two milling swarms together in level 6, or split one force across two planets in level 7 and three in level 8. Every entry is published to the companion website and browsable in-game from My Entries.
  • Visual block editor. Build per-species behavior by stacking condition and action blocks — no coding required.
  • Custom species. Tune speed, turn rate, vision range, and field of view, or start from the Hunter, Scout, and Worker presets.
  • Resizable arena. Simulate swarms on custom-sized maps with free camera pan and zoom, plus walls and obstacles.
  • Spawn zones. Draw zones that bring in new robots of a chosen species mid-run, driven by the arena program in the block editor.
  • Save, record & replay. Save setups, record live runs, and scrub them back on an interactive timeline.
  • Take-over control. Drive any robot mid-simulation with the keyboard or a gamepad, including a 2-player multiplayer mode.
  • Pixel-art game shell. An animated home screen and menus themed independently from the simulator.
  • Video export. Render recorded runs to H.264 MP4 via a bundled ffmpeg binary, with one-click reveal in the file manager.

Getting started

  1. Open the project in Godot 4.6 (or newer) and press F5.
  2. From the home screen, choose Play for your base (enter a callsign on first launch), or Simulator for the sandbox.
  3. In the simulator, pick a species, left-drag to place robots, press Start, then save/replay/export from Manage Setups.

Player base

Reached from Play — your home planet sits center-screen with unlocked moons orbiting it, over the animated starfield:

  • Home planet & moons. A procedural Terran-Wet planet plus No-Atmosphere moons, each generated from its own saved seed — terrain, palette and spin all come from that seed, so every moon is distinct and looks identical every run. Moons revolve on their own random orbits, passing in front of and behind the planet.
  • Progression. Earn XP to level up; moons unlock with level (up to 5). AstroCoin is the in-game currency. Username, level, XP, coins, and all seeds persist to a local config file.
  • Level rewards. Winning a level pays 25 AstroCoin and 40 XP on Level 1, plus 5 coin and 10 XP for each level number after it, every time it is won. Capturing every evader on Level 2 adds 15 coin and 20 XP.
  • Entry rewards. Every finished entry is claimed from My Entries for XP and AstroCoin. XP only pays when the entry beats your best on that level, but coin pays every time: 10 + 15 x level number x success rate, so a Level 4 entry at 80% pays 58 coin. Only 5 entries per level pay coin in any 24 hours, which stops one algorithm being resubmitted for coin; later entries still pay XP. Upgrades are priced so that buying them takes several entries.
  • Shipyard moon. The first moon unlocked after Hivemind. Upgrades raise the highest value your ship programs may set for Max Speed (4.0 to 10.0 m/s), FOV (90 to 180 degrees), View Distance (7.5 to 12.5 m) and Turn Speed (180 to 360 degrees/s) over five levels costing 40, 80, 120, 160 and 200 coin. Addons are one-time purchases that unlock a block: Thrusters (150 coin) unlocks Throttle, and ships that throttle show a thruster flame.
  • Genome moon. The second moon, unlocked by reaching commander level 4 or by completing Level 4, whichever comes first; until then the workspace has no genome switcher and levels have no genome picker. Every algorithm is a genome, and up to 12 are kept here as cards showing their size, a preview of each stack and when they were last edited. New starts a genome from the default program, Copy duplicates one, and Rename and Delete organize them (the last genome cannot be deleted). One genome is active: it is the program every level flies and every upload sends. Edit makes a genome active and opens it in the Hivemind workspace, whose top bar now switches the active genome and has Save as New to branch a copy. Genomes are saved to user://genomes.cfg, and algorithms saved by older builds are moved in the first time the game starts. Each genome has a stable id so future ship species can each fly their own.
  • Switching genomes in a level. Levels that use the workspace show a genome picker in the top bar. Picking a genome before launch is free. Once the run starts, a switch needs all three of: a switch left, the 5 second cooldown since the last one finished, and fewer live defenders than at the last switch (or at launch). Only the attrition levels lose defenders, so in practice mid-run switching happens on Levels 4 and up. Each switch reprograms every surviving defender on the spot and recolors them, one color per genome stage. A run allows 3 switches, and the Genome moon's Level Switches upgrade adds one per level for 250, 500, 750, 1000 and 1250 coin, up to 8, so every extra switch costs more than maxing a whole Shipyard upgrade. Restarting refills the switches, and Level 7 carries them across both planets.
  • Switch schedules in entries. An entry with mid-run switches uploads its genome schedule: the launch genome with the starting defender count n, then each switched genome with the live defender count n it took over at. The benchmark replays it: when a trial's line falls to the same share of its starting size, the surviving defenders switch program. Replays and the entry page color each stage the same way the game does.
  • Achievements. Besides the original six, there are badges for keeping 5 genomes (Gene Pool), filling every genome slot (Full Library), switching genomes mid-run (Adaptation), winning after a mid-run switch (Evolution), travelling to a newly unlocked moon (New Horizons), the first upgrade or addon (Shipwright), maxing every Shipyard upgrade (Fully Loaded) and maxing Level Switches (Long Game).
  • Moon unlocks. When a moon with a scene unlocks, the next visit to the base plays a reveal of that moon and the Travel button takes you straight there. Each moon plays Dr. Blob's tutorial the first time it is opened.
  • First launch. A modal asks for your callsign before you claim your planet.

The top-right buttons open Moons, Shop (currently disabled), and the ship Workspace; choose a game mode (Timed Local) and press Find Match to play. Online matchmaking isn't wired up yet.

Timed Local

Deploy up to five ships (left-click + drag in your deploy zone) to wipe out the protector swarm orbiting the star before time runs out. Middle-drag to pan, scroll to zoom. Lose your whole fleet and it's game over.

Raiders. A squad of enemy ships defends the protectors. Rather than orbiting, they run a block program of their own: wander the arena, turn away from the star/planet and the outer rim to stay in play, and face-and-fire on any of your ships they spot — so they roam in to intercept your attack.

Survive

A local two-player mode, picked from the game-mode dropdown next to Levels. Two commanders, two home planets, and one two-minute match on a split screen — the left half follows player 1, the right half follows player 2.

Dr. Blob opens every match with a click-through tutorial: he stands bottom-left with his line in a text box beside him, and an animated panel above it demonstrates each point with the real ship sprites. His script lives in va/survive/voice.md; drop line_01.mp3, line_02.mp3, … next to it and the tutorial plays them.

Ready up. After the tutorial each player presses their drive key (or gamepad A) to ready. When both are ready a 5-second countdown starts; either player pressing the key again unreadies and cancels it.

  • The swarm. 24 purple ships spawn across the map and Lévy-walk on their own. The moment one gets any other ship in its vision cone — a player, a blue ship, or another purple one — it turns blue. It reverts to purple after 5 seconds with nothing in sight. Nothing in the arena collides except the outer rim — ships pass straight through each other and through the planets — so herding is purely a matter of what they can see.
  • Blue behavior. 3.4 m/s, 50° FOV, 4.5 m vision, always moving forward and turning left at 90°/s, turning right at 90°/s when it sees an ally — so a herd settles into a cluster and holds position. Park that cluster on your planet.
  • The waves. No evaders for the first 40 seconds. Red evaders then spawn every 5 seconds from t=40 to t=60, cool off, and spawn again from t=80 to t=100 — 10 in total, alternating targets so each planet gets exactly 5. They fly straight at their target and explode on contact; each one that lands is a point against that player.
  • Defense. A blue ship that sees an evader destroys it with a laser at 100% accuracy and self-destructs in the same instant. One blue for one red, which is why the swarm is stocked well deeper than the evader count.
  • Stealing. Nothing anchors a blue ship to the base it was herded to — fly into your rival's base and herd their defenders away.
  • Freeze. Two charges each for the whole match (Q for player 1, / for player 2, or the right shoulder button); a charge locks the rival's ship for 15 seconds. The remaining charges show as snowflake pips down the outer edge of each player's half, and a FROZEN countdown appears there while a freeze is running.
  • Winning. Fewest evaders on your planet when the clock runs out. Equal counts is a tie.

Controls. Player 1 flies the gold ship on WASD, player 2 the green ship on the arrow keys. Controllers are never picked up automatically — press A on a pad and it attaches to the next free player slot, so only the pads you actually want are used no matter how many are plugged in. B detaches it again, and a pad that disconnects releases its slot. Each player's readout shows which device is driving them, [ KEYBOARD ] or [ GAMEPAD ] with the pad's name.

Research data. Each player's APM (actions per minute) is sampled every 5 seconds across the match — this runs in the background and is never mentioned in the tutorial. The end-of-match screen announces the winner over a full stat table (evaders through, defenders left, ships herded, freezes used, actions, average and peak APM), and the same report is uploaded and published on the companion website under Survive.

Sur2

A short cut of Survive made for recording video, listed as Sur2 in the game-mode dropdown in dev mode only. Nothing from it is uploaded.

  • No power-ups. No freezes and no calls, so the pilots can only herd.
  • Capture by touch. A blue ship no longer lasers an evader it sees; it has to touch it, and the capture destroys both ships.
  • No setup. No tutorial and no ready-up: the match opens on a 3-second countdown, and the screen carries no APM, device or hint readouts.
  • One minute. The match runs 60 seconds. Ten evaders arrive one every 3.5 seconds from t=15, alternating planets.
  • Genomes. Player 1 takes the first genome of the loadout and player 2 the second (the whole bank is used when the loadout holds fewer than two). Blue ships herded by a player run that player's genome in its color, and the genome name shows in each player's panel.
  • Sent evaders. Every evader is sent by the rival: it flies on the rival's genome with a steady pull toward its planet, tinted toward the rival's color.
  • Jump gates. The left and right edges are linked gates. A pilot crosses instantly; any other ship that drifts in comes out on the far side 2.5 seconds later.

Levels

The Levels screen lists eight FARP levels. Levels 1 to 6 defend (or attack) the same central planet, level 7 runs over two of them, level 8 over three, and all of them measure the same three events:

Event Definition
Detected The first time any defender sees the evader inside its vision cone.
Captured The first time any defender physically touches (collides with) the evader.
Goal time The time the evader reaches the center planet.

Seeing the evader is not enough to stop it — a defender has to reach out and touch it.

On Levels 1 and 2 a run ends the moment either happens: a capture wins it, the evader reaching the planet loses it. Levels 3 to 5 do not stop at the first capture. They keep sending evaders and score the share the line destroyed, and the result reports how many got through. On Levels 4 and 5 a capture also destroys the defender that made it, so those results report the number of defenders lost as well.

Level 4 plays five waves in game, which is enough to feel out an algorithm without sitting through a four-minute run. The server does not stop at five: it keeps throwing waves until your line is spent or the simulated clock runs out, so a defense that only survives the opening will score far worse on the benchmark than it looked in game.

  • Level 1 — Defense · Place. Drag inside the blue ring to place between one and six defenders, aiming each one's vision cone with the drag direction; right-click one to remove it. Program how they all move and scan in the Workspace, then press Launch Evader. Your layout is saved between sessions.
  • Level 2 — Defense · Ring. You pick 5, 25, 50, 100, 250 or 500 defenders, scattered at random positions and orientations inside the ring, spaced apart so they never clump, and you cannot move them — only the algorithm decides the outcome. Reroll scatters them again. The layout on screen when you launch is the one the server benchmarks, so it is saved between sessions and only Reroll changes it. After a ten second head start the level sends two evaders per defender, one after another, spaced so the stream lasts about 30 seconds (see Evader scaling below). In game the run is a win when a majority of the evaders are captured, and capturing every one pays a bonus; the server benchmark still scores the capture success rate as before.
  • Level 3 — Defense · Waves. You pick 5, 25, 50, 100, 250 or 500 defenders, scattered as in Level 2, and Reroll works the same way. The level plays two waves, each sending one evader per defender all at once around the red ring, with the second launching 1.5 seconds after the first is resolved. A defender that touches an evader destroys it and keeps hunting, so nothing is spent. The score is the share of evaders destroyed alongside how many reached the planet.
  • Level 4 — Defense · Attrition. Five scattered defenders face five waves of one evader at a time, each from a fresh random bearing on the red ring, with one rule changed from Level 3: a capture destroys the defender as well as the evader. Five defenders buy at most five kills, and every one of them thins the line that has to cover the rest of the sky. The run ends early if the last defender is gone, and the result reports the defenders lost as well as the evaders through.
  • Level 5 — Defense · Siege. No waves. Five evaders spawn at once, spread around the edges of the arena rather than a ring, and all drive at the planet, so they arrive in a stagger. A capture still destroys the defender that made it. The run plays out until every evader is destroyed or has reached the planet.
  • Pilot (hidden) — Evasion · Pilot. No longer listed in the Levels screen; the level files remain under levels/modes/level9. You fly the evader yourself against the best Level 2 algorithm submitted by another player, standing exactly where that player placed their defenders; their name is shown in the top bar. (With no entries on the server yet, you face a house algorithm on a fixed ring.) Drag on the red ring to pick your start point, then drive with the movement keys from your Settings (WASD or the arrow keys by default). A three-minute countdown runs in the top right. Reaching the planet wins; reaching it without ever being seen is a clean run, and reaching the planet is worth a large XP payout.
  • Level 6 — Swarm · Merge. Two milling swarms and one player-flown leader. Merge the groups, walk the merged mill onto the planet, then leave and let it hold together without you. The agents see in a 90° cone out to 4.25 m. Holding the two groups merged for one second is enough to pass; the full delivery is the run worth flying.
  • Level 7 — Supply · Allocation. Two planets in two scenes, each with its own seed. Pick 10 or 25 defenders before you start. They all start scattered around planet A and planet B starts empty, and each planet is attacked by half as many evaders as the line holds (5 or 12). Attrition is on: a capture destroys the defender as well as the evader. You fly a gold shuttle that carries nothing and has no vision cone. Every defender runs your workspace algorithm during the deployment window, not just in the fight, and the shuttle reads to their sensors as one of their own — so whatever your WHEN SEES ALLY rule does is how they react to you, exactly as the Level 6 leader steers a mill. Q takes the shuttle dark: a purple shuttle drops off their sensors entirely, so they carry on as if it were not there and you can fly off without pulling them after you. The camera follows the shuttle. The jump gate is the right edge of planet A and the left edge of planet B, so the two planets sit side by side: the shuttle crosses the moment it touches the gate and comes out by the other planet's gate, and any defender that drifts into it crosses too, arriving about two and a half seconds later. Sitting inside the blue placement band, E drops a marker and calls one defender across from the other planet — it leaves purple, flies in through the gate, and settles on the marker facing the heading you had. The deployment window runs thirty seconds, or Begin Assault closes it early, and anything still crossing lands where it was headed. Then every planet is attacked at once: the evaders arrive one at a time over the first minute, each onto a planet picked at random, and every planet faces the same number in the end. A planet you are not standing on keeps fighting live with the split you chose and the one algorithm you wrote. You keep flying through the assault and the gates stay open, for the shuttle and for any defender that drifts in, so you can move between the fights. E still calls a defender across from whichever other planet holds the most, so the split can change while the evaders are landing. The shuttle still reads as an ally, so it can pull a defender onto an evader it never saw, or drag one off the arc it was covering. It can never catch anything itself. A panel on the right tracks both planets at once — a pip per evader, red when one lands and green when one is stopped — so the result on the planet you are not standing on stays readable.
  • Level 8 — Triad · Three planets. Level 7 across three planets. Planet A is the hub: its right edge is the gate to planet B and its bottom edge is the gate to planet C. Planet B's gate is its left edge and planet C's is its top edge, both back to A. Pick 10, 25 or 50 defenders; they all start on planet A, each planet faces a third as many evaders as the line holds (3, 8 or 16), and attrition is on. E calls one defender from whichever other planet holds the most. When the deployment window closes, evaders start landing on all three planets at random, and every planet fights at once.

Dr. Blob's tutorial plays automatically the first time you open each level.

Evader scaling

Levels 2 and 3 size the attack to the line. With D the number of defenders you field:

Level Evaders Timing
2 E = 2 * D One every 15 / D seconds (3 s * 5 / D) after a 10 second head start, so the stream lasts about 30 seconds
3 E = 2 * D Two waves of D at once, the second 1.5 seconds after the first is resolved

Five defenders reproduce the original ten-evader runs. In game Level 2 is won by capturing more than E / 2. The constants are EVADERS_PER_DEFENDER, BASE_DEFENDERS and BASE_SPAWN_INTERVAL in levels/modes/level2/Level2Scene.gd and GROUP_WAVES in levels/modes/level3/Level3Scene.gd; the benchmark worker uses the same equations.

Level shortcuts

Key Action
S Start the run
P Replay — reset and try again
R Reroll the defender scatter (Levels 2 to 5)
E Call a defender across from the other planet (Level 7, deployment window only)
Q Take the shuttle dark so defenders stop sensing it (Level 7)

S, P and R are inert while a run is in progress, since the piloted levels steer with the same keys. E and Q are the other way around: they only work during a Level 7 deployment window.

A Level 1 or Level 2 entry uploads your algorithm and placements, and the evaluation service benchmarks them headlessly: the placement runs grade the layout you submitted against many enemy approach angles, then a ring-sweep measures detection and capture rates against defender count. A Level 3, 4 or 5 entry is benchmarked as an assault instead: 100 trials, each with its own defender scatter and spawn bearings, Level 3 runs its two waves of one evader per defender, and Levels 4 and 5 run far past what the level plays — until the defenders are spent or the clock stops — followed by a sweep that grows the defender count until the algorithm holds cleanly. A Level 6 or 7 entry uploads the recorded flight itself — every defender and evader movement — which the server renders into a watchable replay rather than re-simulating. A Level 7 recording holds both assaults back to back in one replay.

Only the current game version may submit. The server rejects an older build with a clear message rather than filing its entry, because level ids have moved between releases and an old client would file its run under the wrong level.

My Entries lists every entry you've submitted across all eight levels, each with a Claim XP button right in the list — it reads Pending until the server finishes processing the entry, and shows the amount once claimed. View opens an info screen pulled live from the server: capture and detection rates plus the outcome breakdown for a benchmarked level, or the result and the detected / captured / reached-planet times for a piloted run. XP is awarded from your best result on a level, so re-claiming a worse entry pays nothing.

Controls

  • Place robots / deploy ships — left-click + drag (Place Robots tool in the simulator, or inside the deploy zone in Timed Local); the drag direction sets the facing.
  • Robot menu — right-click a robot to take over, release, remove, toggle its trail, or pin its coordinates.
  • Camera — middle-mouse drag to pan, scroll wheel to zoom.
  • Drive a taken-over robot — WASD / arrow keys, or a gamepad's left stick.

Block reference

Behavior is built from four block types:

  • Config — set a physical parameter (speed, turn rate, vision range, FOV, size). Config blocks apply whenever they run, so they can be placed under any event or If block, not only On start.
  • Condition — start a rule (On start; Always; Every [N] seconds; When I see anyone / nobody; When I don't see [a target]; When I touch / don't touch / see a wall). The simulator adds When I see / don't see a [species]; the ship workspace instead adds When I see an enemy / ally.
  • Logic — branch inside a rule (If I see / don't see anyone / an enemy / an ally / an object / a wall / a [species]; If I touch / don't touch a wall; Else if versions of each; Else).
  • Action — run while the condition holds (move, stop, random walk, turn, face target, throttle, and — in the ship workspace — fire).

Actions placed before any condition run under Always. Every [N] seconds runs its blocks through once each time N seconds of simulation time pass; if the blocks are still running when the next interval is due, that run starts as soon as they finish. Random walk steers on a Lévy-flight pattern: mostly short hops with the occasional long straight run. For branching, place an Else block directly after its If at the same level — the Else runs when that If's condition was false. Else if blocks go between them: each one is checked only when every If / Else if above it in the chain was false, and the first one that matches skips the rest of the chain.

The FARP ship workspace shares the simulator's block set (minus the variable blocks): it swaps the species conditions for enemy/ally detection, and hides the Fire, Throttle, and Set size blocks, since a FARP defender stops the evader by intercepting it rather than shooting it. Sliders also accept keyboard arrow keys once focused.

Spawn zones

Spawn zones are simulator only.

  1. Pick a species swatch in the top bar, then choose the Spawn Zone tool and left-drag a rectangle. The zone takes the selected species.
  2. Right-click a zone while the run is stopped or paused to Use the currently selected species, set whether it starts on or off, or Remove it.
  3. Open the Workspace and select the Arena tab. This is the arena program: it runs once for the whole arena rather than once per robot, so a spawn block fires once no matter how many robots are on the map.

A zone does nothing on its own. The arena program drives it with these blocks:

Block What it does
Every [N] seconds Event that runs its blocks each time N seconds pass.
Spawn [count] robots in [zone] Adds robots of the zone's current species at random points inside it, facing random directions. Does nothing while the zone is off.
Set [zone] species to [species] Changes which species the zone spawns for the rest of the run.
Turn [zone] on / off Enables or disables spawning for the rest of the run.
If [zone] has [op] [N] robots Condition on how many robots of any species are inside the zone right now.

The arena program also has On start, Always, the variable blocks, If [variable], Else, and Stop / Pause simulation. Changes a block makes to a zone last only for the current run; Stop puts every zone back to its saved species and on/off state. The arena holds at most 600 robots, so spawns past that are dropped.

Zones and the arena program are saved with setups and runs. Robots that spawned during a recorded run appear in its replay and video export at the moment they spawned.

Default species

Species Speed Turn rate Vision FOV Default behavior
Hunter 5.25 m/s 3.0 rad/s 5.5 m 55° Face anyone it sees
Scout 3.75 m/s 2.0 rad/s 4.5 m 110° Random walk
Worker 2.4 m/s 1.4 rad/s 3.25 m 180° Turns around when it sees anyone

All move forward by default; add your own species with the + button.

Recording and replay

Starting a run records every robot's position and rotation in the background; on Stop or Clear it's saved as a .run file. Load one from Manage Setups to scrub it back and forth on an interactive timeline.

Uploading to the website

Select a run in Manage Setups and press Upload. Give the entry a title and an optional description, and it is published under the website's Simulator game mode with the full recording, every species with its settings and blocks, the arena program, and the arena's walls, obstacles and spawn zones. Uploading needs a commander profile, created the first time you press Play, and is limited to ten minutes of recording. Simulator entries are separate from level entries and never touch XP or the leaderboard.

Take-over mode

Right-click a robot and choose Take Over to drive it manually. Control is keyboard-based by default; enable Controller Mode (and Multiplayer for two controllers) in Arena Settings. Controlled robots show a P1/P2 badge — press Esc or the gamepad's B to release. Stopping or clearing the arena releases all of them.

Video export

From Manage Setups, Export to Video renders a recorded run to an H.264 MP4 through a bundled ffmpeg binary, then offers a one-click reveal of the output folder.

Player settings

Display (window mode, resolution, with Apply buttons), graphics (V-Sync, FPS cap, anti-aliasing), rebindable keybinds, audio volumes, and a Player tab to reset your profile — all persisted between sessions.

Building from source

The project targets Godot 4.6. Clone the repository, open project.godot, and use Project -> Export to build for Linux, Windows, or macOS. See bin/README.md for bundling the ffmpeg binaries used by video export.

Benchmarking

Submitted entries are graded off-engine. The game client uploads the algorithm, the placements, and (for levels 5 and 6) the recorded flight; the astroworker service in the companion web repository re-implements the match loop in Go and runs the trials itself. The game no longer ships a headless benchmarker and no dedicated-server build is needed.

Releases

Contributors

Languages