Build a robot. Arm it. Send it to war.
BuildBattle is a modular, physics-driven robot construction & combat sandbox for Unity — a spiritual successor to Robot Arena 2. Design a chassis from scratch, pack it with parts inside-out, paint it, validate it, then drive and fight it in a physics test garage. This handbook teaches you everything: playing, building, customizing, and extending the kit with your own content.
New here? Read this top to bottom — each section builds on the last. Already comfortable? Jump straight to the Component Catalog, Developer Tools, or Extending the Kit.
Overview
Everything in BuildBattle is built from simple primitives — the depth lives in the mechanics, not the meshes. Two ideas explain the whole kit.
Code-first & data-driven
One master registry of part types (PartCatalog) is the single source of
truth. The build palette, placement rules, physics, save files, and baked prefabs are all
derived from it. Add one part and it flows through the whole kit.
Real physics, real damage
Bots are rigidbodies wired with hinges and welds. Weapons deal a two-axis (piercing / concussion) blow, armour hardness resists it, and every wheel and weapon takes localized damage — wheels pop off, spinners go unbalanced.
Procedural, but bakeable
Parts, chassis, arena, sounds and FX are generated from code, then a one-click
Bake Asset Library projects them into normal Unity assets (prefabs, materials,
meshes, .wavs) you can drag around.
Built to extend
Adding a component, weapon, material, paint colour, sticker, sound, FX, or a whole new bot is a small, well-documented catalog edit — and unit tests guarantee anything you ship can be hand-built by a player.
How the pieces fit together
A robot is a BotDefinition: a procedurally-built chassis plus a list of
parts, each snapped to the floor or onto another part's socket. You assemble it in the
Workshop, then spawn it in the Garage where
BotSpawner turns each part into a live rigidbody, hinge joint, or weld.
The sandbox aesthetic is intentional. Boxes, cylinders, discs and bars keep the focus on engineering and physics. When you extend the kit you compose the same primitives — there are no art pipelines to fight.
Install & Requirements
BuildBattle is a Unity package folder. Drop it into a URP project with the new Input System enabled and you're ready.
| Dependency | Version / Notes |
|---|---|
| Unity | 6000.4.0f1 (Unity 6) or newer |
| Render Pipeline | Universal Render Pipeline (URP) — must be the active pipeline |
| Input System | com.unity.inputsystem (new Input System backend) |
| Test Framework | com.unity.test-framework (for the included EditMode tests) |
The project ships URP render-pipeline assets in Assets/Settings/ and an input map at
Assets/InputSystem_Actions.inputactions. If you drop BuildBattle into an existing
project, make sure URP is active and the new Input System backend is enabled
(Edit ▸ Project Settings ▸ Player ▸ Active Input Handling).
First thing to open: the menu Tools ▸ BuildBattle ▸ Hub. It auto-opens once
per session and is the one-stop panel to open scenes, bake the asset library, capture screenshots,
and open the docs. See Developer Tools.
Quick Start
From a fresh import to driving your first robot in about a minute.
-
Open the Hub
Menu:
Tools ▸ BuildBattle ▸ Hub. From here you can open any scene, bake assets, capture media, and reach this documentation. (It also opens automatically once per session.) -
See it instantly
Open
Assets/BuildBattle/Demo/Showcase.unity— a lit arena with the pre-made bots laid out and framed by a camera. (Generated by the Asset Library baker.) -
Play the Workshop
Open
Assets/BuildBattle/Scenes/Workshop.unityand press Play. The step-by-step wizard walks you through footprint → height → armour → components → paint, or start from a complete pre-made bot. Validate, then hit Test to enter the garage. Full walkthrough in The Workshop Wizard. -
Fight in the Garage
Drive, spin up your weapon, and press F to spawn an opponent — or P to sit back and watch an AI-vs-AI brawl. Controls below.
Garage controls
Why scenes show a "preview" you can't edit at runtime: BuildBattle builds its real,
playable world procedurally on Play (camera, lights, arena, UI, bots). Each scene also
carries an editor-only EditorScenePreview so it isn't empty when you open it;
BuildBattleApp removes that preview the instant the procedural build starts.
The Workshop Wizard
The Workshop is a guided build wizard. It takes you from a bare footprint to a battle-ready, validated robot — and every step enforces the same rules the physics simulation uses, so a bot that builds is a bot that fights.
The build flow
Open Scenes/Workshop.unity and press Play. You can either start a fresh chassis or pick a
pre-made bot and modify it. The wizard advances through these steps:
-
Base Shape — draw the footprint
Sketch the chassis floor on a 0.05 m grid. This is the bot's footprint; everything else rests on or inside it. The mass budget for your weight class is shown live.
-
Height — extrude the shell
Pull the footprint up into a 3-D shell. Taller shells weigh more (armour volume) but enclose more internals.
-
Armour — pick a material
Choose Plastic, Aluminum, Titanium, or Steel. Each trades density (weight) against a health multiplier and a hardness that resists piercing damage. See Weapons & Damage.
-
Components — pack it inside-out
Place a control board, battery, drive motors + wheels, and any weapon. The shell turns see-through so you can position internals precisely. Parts snap to the grid or glow-snap onto compatible sockets. Live panels show mass, power, top speed, weapon damage, and a pass/fail validation.
The bot is seated on the floor under live physics as you build: add a wheel and the whole machine smoothly rises to ride on it, so nothing ever clips through the baseplate, and loading a pre-made bot drops it onto its wheels instantly. What you see resting in the workshop is the stance it fights with.
-
Paint Shop — finish & mask
Wash the armour with a colour, stick on livery, and place functional hole/slot masks where weapon shafts pass through the shell. See the Paint Shop section.
-
Validate & Test
The validator confirms the bot is legal (has a brain, a battery, 2+ driven wheels, fits its weight class, has enough power). Then Test drops you into the garage.
Built inside-out: the build progression
Because you build from the floor up, a finished bot is really layers of legal placements. Here's the same chassis growing from bare shell to complete machine:
Fastest way to learn: start from a pre-made bot (e.g. Bar Spinner), step backward through the wizard, and watch how each layer was placed. Every preset is hand-buildable with exactly these tools — that's a guarantee enforced by tests (see Testing).
Inside the Bot
BuildBattle is an inside-out builder: the interesting engineering is the guts. During the Components step (and in these cutaways) the armour shell goes translucent so you can see exactly how the drivetrain and electronics are arranged.
The anatomy of every robot
- Chassis — the procedurally-extruded armour shell. Its material sets weight, durability, and hardness.
- Control board — the brain. Exactly one per bot, and it's protected from being knocked off so a bot can't be trivially disabled.
- Battery — provides capacity (Wh), pack voltage, and peak output (W). Voltage and wattage are both checked against the motors (see Power Budget).
- Drive motors + wheels — each motor exposes an axle socket; one wheel snaps per axle. Motors at the corners give a wide, planted stance.
- Weapon system — one of three families: a static weapon welded to the floor (wedge, spike, cleaver); a spinner chain (weapon motor → extender → implement); or an actuated weapon hinged to the chassis and fired on command (flipper, hammer, overhead axe).
Because internals sit behind armour, electrical parts (battery, motors, brain) also smoke as the bot's overall health drains — a dying machine visibly cooks from the inside. Pass-throughs (a spinner shaft poking out) can be tidied with hole/slot mask stickers.
Component Catalog
Every buildable part, straight from PartCatalog. Each part has a category
(its behavioural class), a dry mass, hit points (before the armour multiplier), and category-specific
stats. The palette shows these live as you build.
Part categories
Brain & power
| Part | id | Mass | HP | Key stats |
|---|---|---|---|---|
| Control Board | board_basic | 0.4 kg | 25 | draws 5 W · one per bot · undetachable |
| NiMH Pack (S) | battery_small | 1.6 kg | 30 | 60 Wh · 12 V · 1500 W out |
| LiPo Pack (L) | battery_large | 3.2 kg | 45 | 160 Wh · 24 V · 7000 W out |
| Cell Barrel | battery_barrel | 2.2 kg | 35 | 110 Wh · 18 V · 3500 W · cylindrical |
Drive
| Part | id | Mass | HP | Key stats |
|---|---|---|---|---|
| Speed Motor | motor_speed | 1.8 kg | 40 | 1.2 Nm · 4200 rpm · 350 W · 12–24 V (overvolt) |
| Torque Motor | motor_torque | 2.6 kg | 55 | 4.5 Nm · 1600 rpm · 480 W · 12–24 V |
| Wheel (S) | wheel_small | 0.8 kg | 22 | r 0.09 m · w 0.06 m · grip 1.4 |
| Wheel (L) | wheel_large | 2.0 kg | 34 | r 0.13 m · w 0.09 m · grip 1.5 |
Weapon motors
| Part | id | Mass | HP | Key stats |
|---|---|---|---|---|
| Spinner Motor (horiz) | wmotor_spinner | 3.5 kg | 60 | 12 Nm · 5000 rpm · 900 W · 24–36 V · spins flat (Tombstone) |
| Vertical Spinner Motor | wmotor_vertical | 3.6 kg | 60 | 12 Nm · 4600 rpm · 900 W · upright undercutter (Minotaur) |
Weapon implements
| Part | id | Mass | HP | Bite (P/C) | Mount |
|---|---|---|---|---|---|
| Spinner Bar | weapon_bar | 2.4 kg | 70 | 0.60 / 0.25 | weapon mount |
| Beater Bar (30cm) | weapon_bar_short | 1.8 kg | 58 | 0.70 / 0.30 | weapon mount |
| Heavy Bar (70cm) | weapon_bar_long | 3.8 kg | 95 | 0.70 / 0.35 | weapon mount |
| Spinner Disc | weapon_disc | 2.8 kg | 85 | 0.85 / 0.15 | weapon mount |
| Flywheel Disc (40cm) | weapon_disc_heavy | 4.6 kg | 120 | 0.80 / 0.30 | weapon mount |
| Front Wedge | weapon_wedge | 2.0 kg | 60 | Wedge (dir.) | chassis floor |
| Spike Prong | weapon_spike | 1.2 kg | 45 | Spike (dir.) | chassis floor |
| Cleaver Blade | weapon_axe | 3.0 kg | 90 | Axe (dir.) | chassis floor |
P/C = piercing / concussion shares. “dir.” weapons only bite along their working face — see Weapons & Damage.
Actuated frame weapons
These bolt to the chassis floor but, unlike a fixed wedge or spike, they're hinged and driven: they park at a rest pose and swing on command (Space, or the AI when a foe is lined up). See Actuated weapons.
| Part | id | Mass | HP | Action | Mount |
|---|---|---|---|---|---|
| Flipper Plate | weapon_flipper | 2.2 kg | 70 | flings a foe up & over (launch impulse) | chassis floor |
| Hammer Arm | weapon_hammer | 3.6 kg | 95 | rears up tall, slams its head forward/down | chassis floor |
| Overhead Axe | weapon_axe_pole | 3.2 kg | 90 | stands over the deck, chops down on the foe | chassis floor |
Reach & ballast
| Part | id | Mass | HP | Key stats |
|---|---|---|---|---|
| Extender (10cm) | extender_short | 1.0 kg | 55 | relays a weapon mount 0.10 m outward |
| Extender (20cm) | extender_long | 1.7 kg | 65 | relays a weapon mount 0.20 m outward |
| Ballast | ballast_block | 4.0 kg | 50 | inert mass — tune balance & weight class |
Sockets — how parts connect
Parts seat using one shared snap function (SocketSnap), so a placement in the workshop
lands byte-for-byte where a pre-made bot's data put it. Three socket types matter:
ChassisFloor— a part rests on the baseplate (grid-snapped). Most internals and static weapons.MotorAxle— a drive motor exposesaxle_l/axle_r; one wheel snaps per axle.WeaponMount— a weapon motor exposes amountalong its spin axis; an extender or implement snaps on. Extenders re-expose a freshtipmount further out.
Weapons & the Damage Model
How hard a blow lands is a two-axis model lifted from Robot Arena 2, all living
in CombatMath. Understanding it is the key to designing both weapons and armour.
Piercing vs concussion
Every weapon's bite splits into two shares (a WeaponDamageProfile):
- Piercing — sharp, armour-defeating force (discs, blades, spikes). Blunted by hard armour.
- Concussion — blunt force that punches through plate regardless (hammers, rammers, wedges).
The pair feeds the RA2 damage potential, surfaced as dmg N in the part picker:
D = 183.9 · piercing + 100 · concussion
Armour hardness resists piercing — not concussion
Each material carries a hardness on the RA2 scale. Harder shells shrug off the piercing share of a hit while concussion sails straight through. So a sharp spinner wants a soft target, and a blunt hammer doesn't care what you're made of.
| Material | Density | HP × | Hardness | Takes ~ of a sharp hit |
|---|---|---|---|---|
| Plastic | 1200 kg/m³ | 0.5× | 80 | ~125% |
| Aluminum | 2700 kg/m³ | 1.0× | 100 | ~100% |
| Titanium | 4500 kg/m³ | 1.6× | 150 | ~68% |
| Steel | 7850 kg/m³ | 2.0× | 175 | ~57% |
Directional weapons only bite along their face
A profile may set UsesDamageNormals with a local working direction and a tolerance cone.
A front wedge bites forward/up, a fixed spike straight ahead, and a
nose cleaver chops forward-and-down. Glancing or reversed hits are trimmed down to a
minimum factor. Spinners stay omnidirectional — a whirling bar hits with whatever
edge meets the enemy.
At runtime CombatHitDealer.WeaponContactDamage layers it all on top of the solver
impulse: impulse sets the energy, the profile scales it, armour hardness blunts piercing, and the
directional factor trims off-axis blows. Frame-welded static weapons are tagged with a
WeaponSurface so the chassis dealer upgrades their contacts from a generic ram into a
real, directional strike.
Reach: motor → extender → implement
Spinners that need to clear the chassis don't cheat their geometry — they chain a weapon motor to an extender to an implement. A horizontal spinner lifts its bar on an extender; a vertical spinner instead raises its motor on a bracket (an extender would push the disc sideways, not up). The shipped Vertical Saw demonstrates the correct floor clearance.
Actuated weapons: flippers & hammers
Not every weapon spins. Flippers, hammers, and the
overhead axe are hinged to the chassis and driven on command rather than run
continuously. Each parks at a rest pose, and a fire input swings it through its stroke and back, then
re-arms — a state machine (Idle → Firing → Holding → Returning) in
WeaponController drives the hinge motor to the target angle for each phase.
- Flipper — a low plate at the nose, hinged at its rear edge. Firing whips the front edge up; on top of the contact damage it hands the victim a mass-scaled upward launch impulse at the strike point, so a foe that drove onto it is flung up and over rather than just nudged.
- Hammer / Overhead Axe — a tall arm that stands cocked over the deck and slams its head forward and down onto a foe in front. The axe carries a sharper, lighter head that bites as it chops; the hammer leads with blunt concussion.
Fire with Space (the same key spins a spinner up). The AI
(EnemyAIController) fires automatically when an opponent is inside a heading cone and
close enough to connect, so flipper and hammer bots fight themselves in AI-vs-AI. A fired hinge reads
its angle straight from the solver, so the swing is honest physics — the same launch and slam are
pinned by the live-physics playtests in Testing.
Power Budget
Power is checked on two axes — voltage and wattage — just like a real combat robot.
- Voltage: motors declare a nominal and max voltage. Overvolting (e.g. 12 V motors on a 24 V pack) buys speed but must be within the motor's max.
- Wattage: batteries advertise a peak output (W); motors a peak
demand.
BotStatsCalculatorsums both and the stats panel showspeak / output W.
If your motors can out-pull your packs, the validator raises an advisory warning (the RA2 “brown-out under load” rule) — it won't block the build, but the fix is a bigger or extra battery.
Rule of thumb: the small NiMH pack runs a pair of drive motors; a 24 V spinner build wants the large LiPo pack. Stacking heavy motors on a small pack trips the warning.
The Garage
The garage is a physics test arena. Drive your bot, spin its weapon, summon an opponent, and watch parts come apart under real impacts.
Controls recap
Impacts spark and clang, weapons whir as they spin up, and a knock-out triggers a blast, smoke and a stinger. Press F to spawn a sparring opponent at any time, or R to repair and respawn your bot.
Localized Part Damage
Combat is more than one health bar. Alongside the whole-bot knock-out pool, each
independent sub-part — every wheel, each weapon assembly, exposed wedges and spikes — carries its own
DamageableBody. Focused punishment cripples a component long before the bot dies.
Wheels degrade, then break off
A worn wheel makes less torque and tops out slower (the bot pulls to one side). Past a threshold the tyre pops — grip is cut and you see a squash. At zero it tears off its axle and tumbles away as debris.
A damaged spinner spins you out
Every hit a weapon lands wears itself, and incoming hits damage it directly. A worn
weapon becomes unbalanced: it shoves the chassis with a force scaling with the
square of spin speed. Ease the throttle (Q) to tame the wobble — the HUD warns
! UNBALANCED.
Parts smoke, electrics burn
Beaten parts trail rising smoke; a failing battery or motor catches fire. Internals couple to the bot's overall health, so a dying machine cooks from the inside. A torn-off part keeps burning as debris before guttering out.
Debris & banners
Destroyed parts emit their own blast / smoke / boom and flash a HUD banner
(WHEEL TORN OFF!). The control board is spared so a bot can't be cheaply disabled.
The whole system is gated by BuildBattleSettings.enablePartDamage (turn it off for
indestructible parts), wobble by weaponWobbleScale, and smoke/fire by
enableDamageFx. The balance numbers live in one testable place: CombatMath
(PartHpScale, WheelPopFraction, PoppedWheelGrip,
WeaponSelfWearFraction).
Camera & AI vs AI
The arena camera
A single BattleCamera offers five views, cycled with C: two fixed
broadcast vantages (Wide, Ringside) that pan to track the action, and three
chase distances (Far, Mid, Close — scroll to fine-zoom). It's built to stay
watchable under chaos:
- It follows a smoothed focus point, and the chase heading comes from the bot's velocity, not its orientation — a rammed or flipped bot won't whip the view around.
- Rotation is always built against world-up, so the horizon stays level even when the bot rolls.
- Impact shake is small and tunable: set
cameraShakeScaleto0for a rock-steady view.
Watch AI fight AI
Press P (or the Autopilot button) to hand your bot to the AI. It spawns an opponent if needed, switches to the broadcast camera, and lets two evenly-matched AIs fight while you spectate — same brains, drivetrain and weapons on both sides. Press P again to take back the wheel.
The AI (EnemyAIController) is physics-honest: it reads the target's position and writes
arcade input into the same drive controller you use — it never teleports. Because it's
generic, the garage can attach it to either bot, which is exactly how AI-vs-AI works.
Paint Shop
The Paint Shop step finishes a bot's look — and combat then marks it up for real. It's the same data-driven model as everything else, surfaced four ways.
Paint
A row of standard colours is washed over the chosen armour material rather than replacing it,
so steel still reads as steel — just painted. Purely cosmetic (no mass or durability change), saved as
a single paintId.
Stickers & livery
Pick a decal and it ghosts onto the shell, snapping flush to the surface. Place controls:
Functional hole / slot masks
Two stickers read as a bored hole or a machined slot cut into the armour. Place one where a spinner shaft or weapon extender passes through the wall and the spot reads as designed — a clean fix for the inside-out builder's unavoidable pass-throughs, instead of a weapon appearing to clip through solid metal.
Armour that dents (mesh deformation)
Wear marks are painted on; the dents are real geometry. Every blow that lands on the
shell pushes its mesh vertices inward along the surface — a blunt ram leaves a broad bowl, a sharp disc
or axe carves a tight, deep gash, and repeated hits along a path accumulate into a torn channel. The
deformation is permanent for the life of the bot, so a shell visibly crumples over a fight. Only the
rendered mesh is reshaped (and refined on the fly so dents read smoothly across a panel) — the bot keeps
its original convex collision hull, so denting never destabilizes the physics solver. Gated by
BuildBattleSettings.enableDeformation.
Battle scars (automatic)
During a fight the combat system sprays a wear mark wherever a weapon bites, chosen by how sharp the blow was:
Each mark normalizes onto the exact piece the blow struck — the shell, a wheel, or a
weapon — parented to that part's transform and oriented to its surface, so a hit on a tyre scars the
tyre, not the air beside it. Marks carry no colliders (they never disturb physics) and are
oldest-recycled so a long fight stays cheap. Decals are flat, unlit, double-sided transparent quads
sharing one material per texture key, with art generated procedurally and baked to
Resources/Decals/*.png.
Hit marks honour BuildBattleSettings.enableHitDecals; player stickers are unaffected.
Adding a paint colour, sticker, or hit effect is a one-catalogue edit — see
Extending the Kit.
Audio & FX
Sound and particles are procedural-first with bakeable assets, mirroring the rest of the kit.
BBSfx — synthesis
Every cue is synthesised from math — impacts, the looping weapon whir, knock-out boom, UI click,
win/lose stingers — and can be encoded to 16-bit PCM .wav. Deterministic (seeded), so
bakes are reproducible.
BBAudio — playback
A tiny runtime player: pooled 2-D sources for one-shots and a Loop(...) helper for the
whir that rides the bot. Resolves baked clips first, falls back to live synthesis.
BBVfx — particles
Spawns named effect prefabs (sparks, KO blast, smoke), tints and auto-destroys them, and hosts the
looping damage emitters (FX_Fire, FX_DamageSmoke) that beaten parts
drive.
BuildBattleSettings
One inspector gates master / SFX / whir volume and the audio & FX on/off switches — rebalance the whole kit with no code.
Sample Bots
Nine ready-to-drive presets ship with the kit — researched after the archetypes from the Robot Arena series and real combat robots: horizontal and vertical spinners, an overhead axe, a hammer, a flipper, and control bots. Every one is fully hand-buildable in the workshop. Click any image to enlarge.
EnemyBotFactory — press F to summon one.The wide-stance look
Drive motors sit at the corners and a fat tyre seats half its width outboard of the axle face, so wheels stick proud of the shell — the aggressive monster-truck stance real combat robots have, which also lowers the ground line for spinner clearance.
Presets live in BotPresets.cs and are built through the same BotAssembler
a player's placements go through. To add your own, see
Extending the Kit → Add a pre-made bot.
Developer Tools
Everything lives under the BuildBattle menu in the Unity editor. The Hub is
your front door; the rest are one-click bakers and capture rigs.
| Menu item | What it does |
|---|---|
Tools ▸ BuildBattle ▸ Hub | The front-door window: open scenes, bake, capture, jump to settings, open these docs. Auto-opens once per session. |
Tools ▸ BuildBattle ▸ Authoring Tools | A workbench that scaffolds ready-to-paste C# for a new component or bot, opens any catalog in one click, and runs the bake / verify loop. |
Tools ▸ BuildBattle ▸ Create Scenes | (Re)generates the playable Workshop & Garage scenes. |
Tools ▸ BuildBattle ▸ Open Workshop Scene | Opens the build wizard scene. |
Tools ▸ BuildBattle ▸ Add Entry To Current Scene | Drops the BuildBattle entry point into the open scene. |
Tools ▸ BuildBattle ▸ Bake Asset Library | Projects all procedural content into inspectable assets: prefabs, shared materials, meshes, .wav sounds, FX prefabs, and the Demo/Showcase.unity scene. |
Tools ▸ BuildBattle ▸ Bake Sounds && FX | Regenerates just the audio + FX prefabs + settings asset. |
Tools ▸ BuildBattle ▸ Capture Bot Screenshots | Hero + side shot of every preset (headless, to Screenshots/). |
Tools ▸ BuildBattle ▸ Capture FX Preview | A frozen particle-FX preview frame. |
Tools ▸ BuildBattle ▸ Capture Feature Reel | The full set: build progression, battle-worn hero, launch burst, interior cutaways, UI shots, and AI-vs-AI video. |
Tools ▸ BuildBattle ▸ Capture Battle-Worn Hero | Just the deformation + damage-texture hero shot (dents, gash/scorch decals), headless to Screenshots/feature/. |
Tools ▸ BuildBattle ▸ Capture AI Battle Video | Just the AI-vs-AI fight (frames + mp4 if ffmpeg is on PATH). |
Tools ▸ BuildBattle ▸ Capture UI Screenshots | The workshop & garage HUDs composited over a bot. |
Tools ▸ BuildBattle ▸ Capture Scene Previews / Capture Showcase | Renders the scenes / the showcase to Screenshots/ for a quick visual check. |
This very document was generated by the docs build script in
Assets/BuildBattle/Documentation/, which embeds the latest captures from
Screenshots/latest. Re-run it after capturing new media to refresh the screenshots.
Extending the Kit
BuildBattle is code-first and data-driven: one registry of part types is the single source of truth, and the palette, placement rules, physics, save files and baked prefabs are all derived from it. Adding content is a small catalog edit that flows through the whole kit.
The one mental model
PartCatalog (register a PartDefinition)
│ the id is the only thing a save file stores
▼
PartFactory.BuildDetailedVisual ──► a primitive mesh + ONE root collider
│
├──► Workshop: appears in the palette, snaps to grid/sockets, collision-checked
├──► Stats / Validation: counted toward mass, power, legality
├──► BotSpawner: rebuilt as a rigidbody / hinge / weld in the garage
└──► BBAssetBaker: persisted as Prefabs/Parts/<id>.prefab
You almost never edit more than the catalog and (optionally) the factory.
Where to edit, by task
| To add… | Edit… |
|---|---|
| A component | Core/Parts/PartCatalog.cs (register a PartDefinition); optional visual in PartFactory |
| A weapon (with its bite) | PartCatalog.cs — give the WeaponDefinition a WeaponDamageProfile |
| An armour material | Core/Materials/MaterialManager.cs (density, durability & hardness) |
| A pre-made bot | Core/Presets/BotPresets.cs via BotAssembler |
| An enemy archetype | Core/Combat/EnemyBotFactory.cs (also via BotAssembler) |
| A weapon-reach part | PartCatalog.cs — an ExtenderDefinition |
| A paint colour | Core/Decals/PaintCatalog.cs |
| A sticker / hit-effect | Core/Decals/DecalCatalog.cs + a shape in BBDecalTextures.cs |
| A sound | Core/Audio/BBSfx.cs (synth); play via BBAudio.Play(...) |
| A particle effect | Editor/BBContentBaker.cs; spawn via BBVfx.Spawn(...) |
| Re-tune combat | Core/Combat/CombatMath.cs + BuildBattleSettings.asset |
After changing any catalog, re-run Tools ▸ BuildBattle ▸ Bake Asset Library so the
inspectable assets match the code.
Recipe · Add a component
A worked example — a capacitor bank (just mass + looks). Add one line to PartCatalog:
new StructuralDefinition("cap_bank", "Capacitor Bank", 1.8f,
new Vector3(0.09f, 0.06f, 0.07f), 30f, new Color(0.30f, 0.32f, 0.40f)),
That alone makes it appear in the palette, snap to grid, get mass-counted, validate, spawn in the
garage, and bake to Prefabs/Parts/cap_bank.prefab. The constructor families:
new ControlBoardDefinition("board_x", "...", m, dims, hp, drawW, tint);
new BatteryDefinition("battery_x", "...", m, dims, hp, wh, volts, maxW, cylindrical:false, tint);
new DriveMotorDefinition("motor_x", "...", m, dims, hp, torque, rpm, drawW, tint, 12f, 24f);
new WheelDefinition("wheel_x", "...", m, r, w, hp, friction, tint);
new WeaponMotorDefinition("wmotor_x", "...", m, dims, hp, torque, rpm, drawW, Vector3.up, tint, 24f, 36f);
new StructuralDefinition("ballast_x", "...", m, dims, hp, tint);
To give it a recognisable look, add a case to PartFactory.BuildDetailedVisual(...). Keep
the collider a single authoritative box/capsule/sphere on the root — never on visual children.
Recipe · Add a weapon
Weapons also describe how hard they hit. Use a ready-made profile or build your own:
WeaponDamageProfile.Spinner(piercing, concussion); // omnidirectional, sharp-ish
WeaponDamageProfile.Blunt(concussion, piercing); // omnidirectional, blunt
WeaponDamageProfile.Wedge(); // directional, forward/up, blunt
WeaponDamageProfile.Spike(); // directional, dead-ahead, sharp
WeaponDamageProfile.Axe(); // directional, forward-and-down chop
WeaponDamageProfile.Hammer(concussion, piercing); // heavy slam (hammer / overhead axe)
WeaponDamageProfile.Flipper(); // light blunt — the launch does the work
A spinning implement bolts onto a weapon mount (default):
new WeaponDefinition("weapon_flail", "Chain Flail", 1.6f,
new Vector3(0.06f, 0.06f, 0.30f), 55f, new Color(0.7f, 0.7f, 0.75f),
WeaponDamageProfile.Blunt(concussion: 0.6f, piercing: 0.2f),
PrimitiveShape.Bar),
A static, frame-welded weapon bolts to the floor — set the parent socket:
new WeaponDefinition("weapon_plow", "Forged Plow", 2.4f,
new Vector3(0.26f, 0.06f, 0.18f), 70f, new Color(0.6f, 0.62f, 0.68f),
WeaponDamageProfile.Wedge(), PrimitiveShape.Box, SocketType.ChassisFloor),
An actuated weapon adds an actuation type and hinge parameters — it's mounted to the
chassis floor and swung by WeaponController, not welded. A flipper also carries a
launchSpeed for the mass-scaled fling:
new WeaponDefinition("weapon_flipper", "Flipper Plate", 2.2f,
new Vector3(0.30f, 0.05f, 0.22f), 70f, new Color(0.66f, 0.68f, 0.74f),
WeaponDamageProfile.Flipper(), PrimitiveShape.Flipper, SocketType.ChassisFloor,
WeaponActuation.Flipper, hingeLocalAnchor: new Vector3(0f, 0f, -0.11f),
hingeAxis: Vector3.right, swingDegrees: -72f, swingSpeedDegPerSec: 620f,
swingTorqueNm: 220f, launchSpeed: 4.2f),
Vertical-spinner geometry caveat: a vertical motor's mount axis is lateral, so an
extender pushes the disc sideways, not up. To raise a vertical disc, raise the
motor with a heightOffset (a real bearing bracket) — never an
extender. The shipped Vertical Saw shows the pattern.
Recipe · Add an armour material
[MaterialType.Carbon] = new ArmorMaterial(
MaterialType.Carbon, "Carbon Fibre", 1600f, 1.3f, 0.004f,
new Color(0.12f, 0.12f, 0.14f), 0.2f, 0.6f, 120f),
// type, name, density, healthMult, shellThickness, tint, metallic, smoothness, hardness
Add the enum value to MaterialType first. The workshop's material step and the weight
calc pick it up automatically. Hardness resists the piercing share of hits.
Recipe · Add a pre-made bot (kept hand-buildable)
Author through BotAssembler — a “virtual workshop” that obeys the exact placement rules
the live UI enforces:
private static BotDefinition BuildHammerBot()
{
var def = NewChassis("Hammer", MaterialType.Steel);
var b = new BotAssembler(def);
AddCornerDrive(b); // 4 corner motors, one wheel each
b.Floor("board_basic", 0f, -0.15f); // x, z on the 0.05 m grid
b.Floor("battery_large", 0f, -0.05f);
string wm = b.Floor("wmotor_spinner", 0f, 0.10f); // weapon motor on the floor
string ex = b.Attach("extender_long", wm, "mount"); // extender onto the mount
b.Attach("weapon_bar_long", ex, "tip"); // implement onto the tip
return def;
}
Then register it in the _all preset list with a name and one-line blurb. The API:
Floor(id, x, z, heightOffset = 0, euler = default)— drops a floor part; snaps to the grid, rests on the baseplate, then raises/tilts.Attach(id, parentInstanceId, parentSocketId)— bolts a child onto a real socket, refusing a wrong type or a double-booked socket.
The five rules every bot must satisfy (enforced by tests)
- Sockets are real, correctly typed, used at most once.
- Attachments sit exactly where
SocketSnapwould put them. - Floor parts are grid-snapped & bounded; weapons may overhang (only their anchor centre must be over the frame), internals may not.
- No two parts clip (OBB separating-axis test).
- Spinning weapons clear the floor (lowest point ≥ 4 cm above the wheel-contact plane).
Recipe · Add an opponent & its AI
Add a value to EnemyArchetype and a builder (just like a preset), branch to it in
Create(...), and add it to PresetBuildabilityTests.AllBots(). The brain is
generic and wires up in one line:
// GarageBootstrap.SpawnEnemy()
_enemyAI = _enemy.Root.AddComponent<EnemyAIController>();
_enemyAI.Initialize(_enemy.Drive, _enemy.Weapon, _enemy.Health, _bot.Health);
Tunable knobs: SteerFullLockDegrees (heading error → full lock) and
EngageDistance (how close it presses before grinding).
Recipe · Add paint, a sticker, a sound, an effect
// Paint colour — PaintCatalog.cs
new PaintColor("battleship_grey", "Battleship Grey", new Color(0.40f, 0.43f, 0.46f)),
// Sticker / hit effect — DecalCatalog.cs (+ a shape in BBDecalTextures.Sample)
new DecalDefinition("sticker_skull", "Skull", DecalCategory.Sticker, "skull",
0.06f, Color.white, false, "Pirate skull marker."),
// Sound — BBSfx.cs, then play anywhere
BBAudio.Play(BBSfx.Servo, volumeScale: 0.8f, pitch: 1.1f);
// Particle effect — BBContentBaker.cs, then spawn
BBVfx.Spawn(BBVfx.Spray, contactPoint, tint: Color.cyan, scale: 1f);
Ship checklist
- Register the part/material in its catalog; add a
PartFactoryvisual if you want it recognisable. - For weapons, give a
WeaponDamageProfile; for nose spinners, mind floor clearance. - Add bots/enemies through
BotAssemblerand list them in the buildability test. Tools ▸ BuildBattle ▸ Bake Asset Library(orBake Sounds && FX).- Run the EditMode tests until green.
The full, worked manual is Documentation/AUTHORING_GUIDE.md — this
section is the fast index.
Capturing Media
Two headless rigs render straight to Screenshots/ with an offscreen camera —
no play mode, no manual scene. Run with a GPU (do not pass -nographics).
BBShots(Capture Bot Screenshots / Capture FX Preview) — a hero + side shot of every preset and a frozen FX preview.BBReel(Capture Feature Reel) — the full set: a workshop build progression, interior cutaways, a battle-worn hero (real dents + decals + staged smoke/fire), a spinner-launch burst, UI shots, and an AI-vs-AI battle captured frame-by-frame.
The battle recorder spawns two bots, attaches an EnemyAIController to each, and steps a
manual Physics.Simulate loop — driving the real brains, drivetrain and weapons through
their public tick hooks, so the footage is genuine physics, not a canned animation. If
ffmpeg is on your PATH it also encodes an .mp4.
Unity.exe -batchmode -projectPath <proj> \
-executeMethod BuildBattle.EditorTools.BBReel.CaptureAll -logFile reel.log -quit
Set the BB_SHOT_DIR env var to redirect the output folder. Editor windows (Hub,
Authoring Tools, the wizard HUD) aren't rendered by these rigs — grab those with an OS screenshot.
Testing & Verification
A large EditMode suite covers chassis geometry, validation, serialization (including the paint + sticker round-trip), stats/voltage, the combat damage model, the catalogue, presets, the paint shop, battle damage FX, the controller step hooks, audio synthesis, and the actuated weapons — including a live-PhysX playtest that spawns the flipper, hammer and axe, fires them, and asserts the plate really lifts and the heads really slam forward and down.
Run from Window ▸ General ▸ Test Runner ▸ EditMode, or headless:
Unity.exe -batchmode -projectPath <proj> \
-runTests -testPlatform EditMode -testResults results.xml
Buildability is verified, not asserted. PresetBuildabilityTests replays
the workshop's checks over every preset and enemy: real/typed sockets, exact snap
placement, grid + bounds, OBB clip checks, and spinning-weapon clearance — both that a spinner clears
the floor and that it dips low enough to actually strike a foe. A failing buildability test
is a feature — it means a player couldn't make the thing you shipped.
Reference Tables
Weight classes
Set def.weightClass on the chassis; the validator checks total mass against the cap.
| Class | Code | Max mass |
|---|---|---|
| Antweight | AW | ≤ 125 kg |
| Beetleweight | BW | ≤ 175 kg |
| Lightweight | LW | ≤ 249 kg |
| Middleweight default | MW | ≤ 399 kg |
| Cruiserweight | CW | ≤ 600 kg |
| Heavyweight | HW | ≤ 800 kg |
| Super Heavyweight | SHW | ≤ 1200 kg |
| Ultra Heavyweight | UHW | ≤ 5000 kg |
| Giga Heavyweight | GHW | ≤ 10000 kg |
Tune feel without code — BuildBattleSettings.asset
| Field | Effect |
|---|---|
masterVolume, sfxVolume, weaponWhirVolume | Audio mix |
enableAudio, enableVfx | Master switches |
impactSparkColor | Spark tint |
enablePartDamage | Localized part damage / detachment on/off |
enableHitDecals | Spray scorch/scuff/gash/crater marks (stickers unaffected) |
enableDamageFx | Smoke from beaten parts + fire from failing electrics |
weaponWobbleScale | How violently a damaged spinner shakes the bot |
cameraShakeScale | Impact shake (0 = rock-steady) |
Keyboard reference (garage)
Assemblies
BuildBattle.Core ──► BuildBattle.Workshop / .Physics / .UI ──► BuildBattle.App
+ BuildBattle.Editor (editor-only)
+ BuildBattle.Tests (EditMode)
The clean dependency graph keeps gameplay code free of editor and UI concerns.
Folder structure
Assets/BuildBattle/
├── Scripts/ Runtime code (asmdef per folder)
│ ├── Core/ Data, parts, chassis, materials, stats, validation, presets, audio, fx, decals
│ ├── Workshop/ Build-mode controllers (grid, placement, gizmos, selection)
│ ├── Physics/ Garage sim (spawner, drive, weapons, health, combat, AI, damage fx)
│ ├── UI/ Procedural uGUI HUDs + the UI factory
│ └── App/ Entry point, scene flow, ArenaFactory, BattleCamera
├── Editor/ Hub, Authoring Tools, scene builder, bakers, capture rigs
├── Tests/ EditMode unit tests
├── Resources/ Baked textures, audio, FX, decals, settings asset
├── Prefabs/ Baked parts, bots, environment
├── Scenes/ Workshop.unity, Garage.unity
├── Demo/ Showcase.unity (authored from baked prefabs)
└── Documentation/ README, AUTHORING_GUIDE, this handbook
For the deepest detail, read Documentation/BuildBattle_README.md (using the kit) and
Documentation/AUTHORING_GUIDE.md (extending it). This handbook distills both.