fertig-classic-games/src/games/totalannihilation/sprites.md

7.4 KiB
Raw Blame History

Total Annihilation — art spec

Every sheet is optional. data/totalannihilation-artwork.json ships with path: null on all of them, and TAArt.js paints a procedural stand-in at runtime, so the game is fully playable with zero PNG files. Drop a sheet in and it replaces the stand-in with no code change.

To install a sheet: save the PNG under assets/images/totalannihilation/, then set that sheet's path in data/totalannihilation-artwork.json. Nothing else needs editing — the asset manifest resolves every entry in the sheets map automatically (src/data/assetManifest.js), so new sheets never need a manifest change either.


The two rules that make the art cheap

  1. Units are drawn once, facing right. 0 rad is Phaser's +x axis, and the renderer calls setRotation(heading) — so a unit needs exactly one frame, not eight facings. Draw it pointing right, dead centre in its cell.
  2. Units are drawn in neutral grey. The renderer applies setTint(armyColour) per army. Paint in greys with the detail carried by value (light/dark), not hue; any hue you paint is multiplied by the team colour and will read as muddy. Keep the brightest highlight near white so the tint stays vivid.

Terrain is exempt from both: tiles are drawn in full colour and are never rotated or tinted.


Sheets

Sheet name (JSON key) Texture key Cell Cols Contents
arm-units ta-arm-units 64×64 8 ARM mobile units
core-units ta-core-units 64×64 8 CORE mobile units
arm-structures ta-arm-structures 128×128 6 ARM buildings
core-structures ta-core-structures 128×128 6 CORE buildings
terrain-grasslands ta-terrain-grasslands 64×64 9 Grassland tiles
terrain-snowfields ta-terrain-snowfields 64×64 9 Snow tiles
terrain-tropics ta-terrain-tropics 64×64 9 Jungle tiles
icons ta-icons 44×44 10 Command/build glyphs

Frames are numbered left to right, then top to bottom, starting at 0.


Unit sheets (64×64 cells, 8 per row)

Both army sheets use the identical frame layout — that is what lets one unit definition serve every army. spritePx is the on-screen size the frame is scaled to; draw to fill the cell and let the scale do the work.

Frame Unit Drawn as spritePx
0 Commander hull / legs, no weapon 56
1 Commander turret upper body + D-Gun arm 56
2 Infantry whole figure, top-down 30
3 Sniper whole figure, long rifle 30
4 Jeep chassis + wheels 40
5 Jeep turret pintle gun 40
6 Tank hull + tracks 54
7 Tank turret turret + barrel 54
8 Rocket Tank hull + tracks 56
9 Rocket Tank turret rocket pod 56

Turret frames are drawn as a separate image stacked on the hull and rotated independently, so the unit aims while it drives. Rules:

  • The turret's pivot is the centre of the cell — draw the turret so its rotation point sits at (32, 32), with the barrel extending to the right.
  • Leave the rest of the turret cell transparent. The hull shows through it.
  • A unit with no turret (infantry, sniper) simply has no turret frame; its whole sprite rotates to face its target.

Frames 1063 are free. Add a unit by appending a definition to units[] in data/totalannihilation-rules.json with its frame (and optional turretFrame) — no code.


Structure sheets (128×128 cells, 6 per row)

Buildings do not rotate. They are scaled to footprint × 64px, so a 2×2 building renders at 128px and a 3×3 at 192px — draw the 3×3 buildings to fill the cell and accept that they are scaled up 1.5×, or supply a larger cell size in the artwork JSON.

Each building has two frames: the finished structure, and a build frame shown while it is under construction (the renderer also fades it in by build progress). Draw the build frame as a skeleton/scaffold version — girders, no panels, no lights.

Frame Building Footprint Notes
0 Energy Generator 2×2 radiating fins / vents
1 Energy Generator — under construction 2×2
2 Mass Generator 2×2 drill ring; sits on metal patches
3 Mass Generator — under construction 2×2
4 Barracks 3×3 doorway on the bottom edge (units exit downward)
5 Barracks — under construction 3×3
6 Vehicle Plant 3×3 wide bay door on the bottom edge
7 Vehicle Plant — under construction 3×3

Frames 835 are free.


Terrain sheets (64×64 cells, 9 per row)

Every kind: "terrain" sheet must follow this exact frame order — it is fixed in terrainFrames in the artwork JSON, which is what lets a new theme be a pure drop-in:

Frame Tile Notes
0 ground the base tile — most of the map
1 groundAlt1 variation, scattered to break up tiling
2 groundAlt2 second variation
3 rough slows wheeled units; still buildable
4 cliff impassable, not buildable
5 water impassable to current units
6 waterDeep impassable; used for the interior of large bodies
7 metal metal patch — doubles a Mass Generator's yield
8 road fast movement

Tiles must be seamlessly tileable on all four edges, since the terrain is stamped into chunked RenderTextures with no blending. Keep them low-contrast: units and health bars are drawn on top, and busy terrain makes a battle unreadable.

Metal (frame 7) should read as obviously valuable at a glance — it is the one tile the player hunts for.

Adding a new theme

  1. Draw a 9-frame terrain sheet in the order above.
  2. Add it to sheets in data/totalannihilation-artwork.json with "kind": "terrain".
  3. Add an entry to themes naming that sheet, plus a palette giving a colour per terrain id (ground, rough, cliff, water, metal, road, …). The palette drives the minimap and the procedural fallback, so it is required even when a real sheet exists.

The theme then appears in the skirmish setup screen automatically.


Icons (44×44 cells, 10 per row)

Command glyphs for the HUD: move, attack, attack-move, stop, hold, patrol, guard, build, repair, rally. Purely decorative today — the build menu labels itself from unit names — so this sheet is the lowest priority of the eight.


Adding a third army (no code)

Append two sheets (kind: "unit" and kind: "structure") to the artwork JSON, then add a row to armies[] in the rules JSON naming them plus a colour:

{ "id": "hive", "name": "HIVE", "color": "#8ad46a",
  "unitSheet": "hive-units", "structureSheet": "hive-structures" }

Every existing unit and building definition works for the new army unchanged, because each definition references a sheet slot (unitSheet / structureSheet) rather than a sheet name. Add commanders for it in commanders[], pointing opponentId at an entry in data/opponents.json for the portrait.


Checking your work

node tools/verifyTotalAnnihilation.js --quick

Section 2 asserts that every declared sheet has a key and frame size, that each army's sheets exist, that every theme has a palette entry for every terrain type, and that no unit or building references a frame index beyond its sheet's cols × rows capacity — so a mis-numbered frame fails the build instead of rendering the wrong tank in a battle.