All projects

Case study · Solo project

Unicellular

Feb 2025 · Unity · C# · Released on itch.io

An idle simulation built around sheer entity count: thousands of single celled organisms wandering, interacting and multiplying, kept smooth by finite state machines and careful performance work.

  • RoleSolo developer
  • EngineUnity
  • Entities10,000 stress-tested
  • Core techFSM + time-slicing

Overview

An idle game built to scale

Unicellular is an idle sim: you spend currency to buy unicells, they drift around a petri dish living their tiny lives, and the colony's activity feeds the economy back to you. The design means the player is directly incentivised to push the entity count up, so each cell has to stay cheap to simulate or the game's own core loop kills its framerate.

That constraint shaped everything. Behaviour is driven by lightweight finite state machines, but the real trick is when work runs: instead of every cell thinking every frame, the simulation is split across several tick rates and the expensive proximity checks are spread out a batch at a time, all inside Unity's standard GameObject workflow.

On top of the simulation sits a full idle-game economy: seven species of cell, layered upgrades, rare Elder and Shiny variants, a per-species "Souls" prestige currency, and JSON saves so a colony survives between sessions.

The core loop: buy cells, grow the colony, earn faster.

Behaviour

One FSM per cell

Every unicell runs a small finite state machine that decides what it's doing from moment to moment: drifting, seeking, interacting with neighbours. Keeping each state tiny and the transitions explicit does two jobs at once. Behaviour stays easy to reason about and extend, and the cost of "thinking" each frame stays roughly constant no matter how big the colony gets.

Emergence does the rest. With thousands of simple machines running side by side, the dish reads as alive without any cell doing anything complicated.

Cells interacting; each side of the exchange is a state transition.

Performance

Stress tested at 1,000 and 10,000

The recordings below are the two benchmark scenes: a thousand cells, then ten thousand at once, where the counter in the second clip is still reading around 90 FPS. That headroom is what lets the idle economy keep rewarding a bigger colony without the framerate collapsing.

The main levers:

  • A decoupled, multi-rate loop. Core behaviour ticks at 20 Hz, slower bookkeeping like population and levelling runs at 0.5 Hz, and physics work sits in its own pass, so nothing runs more often than it needs to.
  • Time-sliced proximity AI. The expensive "what is near me" queries are the bottleneck, so they are amortised across frames: roughly 150 cells are processed per pass, carrying an index forward until the whole colony has been swept.
  • One manager, not thousands of updates. A single simulation manager iterates the cell and food lists directly instead of every cell running its own per-frame update.
Benchmark one: 1,000 entities.
Benchmark two: 10,000 entities, ~90 FPS on screen.