Until We're Beat

Until We're Beat is a twin-stick "survivors-like," a horde shooter in the vein of Vampire Survivors, where you move and auto-aim through waves of escalating enemies, collect experience, and pick a new weapon or upgrade every time you level up. The twist is that combat is rhythm-synchronized: weapon fire, enemy attacks, and damage-over-time effects all lock to the beat of the music, and the game's simulation speed itself tracks the current BPM, so a run's intensity and its soundtrack are literally the same clock. It's built solo on Unity's Entities (DOTS) framework, with a strict split between the ECS simulation layer and a MonoBehaviour presentation layer that only ever reads from it. The project is data-driven throughout (weapons, enemies, biomes, and items are all authored as swappable config assets rather than hardcoded) and supports mobile touch controls alongside keyboard/mouse and gamepad.

Feature Breakdown

Scope & Architecture

  • ~343 C# scripts, 117 of them independent ECS systems spread across 27 feature areas (combat, enemies, map, movement, weapons, pickups, leveling, rhythm, and more)
  • A strict two-layer split: the ECS/DOTS simulation runs headless and deterministic, while a pooled MonoBehaviour presentation layer reads simulation state and never writes back into it
  • ~15 data-driven config libraries covering weapons, enemies, biomes, drop tables, items, and audio, so new content is authored as data instead of code
  • Touch-control support (virtual stick + dynamic touch zones) alongside standard keyboard/mouse and gamepad input for a mobile target

Rhythm-Synchronized Combat

  • A single global musical clock, ticking down to 1/16-note resolution, that every gameplay system gates its timing off of instead of running its own independent timer
  • Weapon fire cadence, enemy attack windows, and damage-over-time ticks all land on the same beat grid as the music
  • Simulation speed itself tracks the song's tempo, so the pace of a run rises and falls with the soundtrack

Custom Physics

  • A purpose-built collision solver replacing Unity's general-purpose physics for gameplay, designed specifically to handle the hundreds of simultaneous enemies a horde shooter needs
  • A two-pass parallel job design (gather overlaps, then apply) that resolves large numbers of moving bodies per tick without unsafe concurrent writes
  • A sleep system that skips simulation cost for enemies that have settled, keeping performance headroom for the moments that need it most

Data-Driven Weapon System

  • A weapon is modeled as base stats plus a list of independently-timed firing behaviors, so a single weapon can combine projectiles, area hits, and melee strikes with different cooldown rules each
  • Weapon upgrades are a per-level list of composable modifiers (stat boosts, prefab swaps, added firing behaviors) rather than one giant hand-authored table per weapon

Streaming Procedural World

  • An effectively infinite map built from streamed chunks that spawn and despawn around the player as they explore, with biome rules controlling what appears where
  • The same tile grid used for streaming also acts as the spatial index that physics, hit detection, and enemy targeting all query against

Status Effects

  • Fire, frost, poison, electric, and stun are each their own self-contained effect with rhythm-gated tick rates and dedicated visual feedback
  • Electric conducts and chains between nearby entities rather than applying to a single target

Pooling & Performance

  • Zero runtime instantiate/destroy calls: enemies, projectiles, hitboxes, pickups, and their on-screen visuals are all recycled through dedicated object pools
  • Keeps garbage-collection pressure near zero during sustained horde combat, where hundreds of entities are spawning and dying every second

Tooling

  • An in-house in-game profiler that samples per-system timings every tick without needing a profiler attached, exporting results for offline analysis
  • A session analytics system tracking kills, damage by type, per-weapon usage, and player movement across a run, persisted for later review