- Godot 4.7 project; fixed-tick FSM fighter, facing-relative input buffer with numpad motion parsing, box collision, training-mode hitbox overlay - characters/ = self-describing drop-in folders (spec in _spec/); two generated placeholder fighters (alpha, beta) - pipeline/: pack_character.py + autohitbox.py (pose/silhouette hurtboxes) - STUDY.md: reverse-engineering study of the BKB reference games Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
8.5 KiB
FOITIN — Digitized Fighting Game: Source Study & Assessment
Study of Bikini Karate Babes 1 (4 ISOs) + BKB2: Warriors of Elysia (installed copy), cross-referenced with the "Digitized Fighting Game Tech Report" PDF. Goal: build our own original digitized-style fighter with MODELBEAST-generated assets, architected so new characters drop in as data.
1. How the original games actually work (reverse-engineered from BKB2 data)
Engine: Custom C++ on Gamebryo/NetImmerse (.nif scene files), Bink video (binkw32.dll),
Miles Sound System (mss32.dll). 2011-era game.exe is only 1.4MB — the game is almost
entirely data, which is why it worked as a formula.
The core architecture — one video clip per move:
Data/<Character>/ ← one folder per fighter (12 in BKB2, ~75-83 moves each)
bik/<move>.bik ← 512×512 Bink video @ 30fps, actor pre-keyed onto white
zon/<move>.zon ← "BKB!ZONE": per-frame collision boxes (9 zones × 8 ints/frame)
geo/<move>.geo ← "BKB!GEOM": per-frame root-motion / ground-offset track
me2/<move>.me2 ← "BKB!DAT2": move properties (frame windows, damage, links)
csd/ fpd/ off/ ← cancel/sound/offset sidecar data
world.nif ← stage scene
Verified numbers (Venus):
- 81 moves, each its own clip: idle
stand(19f loop), jabhanda(53f), puncheshanda-e, kickskicka-…, specialsspec1/2, blocks, ducks, hit reactions (bhit,lhit,bfall,bkfal…), throws, wins. ~202MB/character. handa.zon: magicBKB!ZONE, 53 frames, 9 collision zones per frame, each zone 8 big-endian ints (type, shape, …, x, y, w, h, flag). Hitboxes AND hurtboxes are hand-placed per frame — this was the labor bomb of the 90s pipeline.handa.geo: magicBKB!GEOM, 53 ints — per-frame X root position (~413px scale), i.e. baked root motion so the character slides correctly during lunging moves.- The full-roster inventory: 3,461 .bik clips across the game (fights, UI slices, VS screens —
even menu elements are positioned video slices named
name-x360-y90-w256-h128.bik).
BKB1 discs: Discs 1–3 are InstallShield cabs (extractable with unshield if we ever want
BKB1's 19-character data), Disc 4 carries the v1.08 patched BKB.exe. Not needed — BKB2's
installed data is the better, complete reference.
What the formula gets right (why it's worth cloning):
- Character = folder of clips + frame-indexed metadata. Adding a fighter = adding data, zero code.
- Frame-indexed everything: collision, root motion, damage windows all keyed to video frame N.
- Uniform base mechanics (the Mortal Kombat doctrine): shared move vocabulary across the roster
(
handa…hande,kicka…,bhit,bfall…) means the engine treats every character identically.
What it gets wrong (what we fix):
- 30fps and a 53-frame jab (1.77s!) — floaty, non-competitive feel. Modern standard: 60fps ticks, jab = 4-8f startup.
- White-keyed 512×512 video → halo edges, no lighting interaction, fixed camera scale.
- Hand-drawn hitboxes per frame — thousands of hours of labor we can automate.
2. Level of detail needed (the real answer)
Per-character clip budget — the minimum viable move set is ~30 clips, not 80
| Category | Clips | Notes |
|---|---|---|
| Locomotion | 6 | idle loop, walk fwd/back, jump (up/fwd/back can share), duck |
| Defense | 3 | stand block, crouch block, block-stun |
| Normals | 8 | 4 punches + 4 kicks (standing/crouching mix) |
| Specials | 3–4 | the character's identity moves |
| Reactions | 6 | head hit, body hit, low hit, knockdown fall, ground, get-up |
| Throw | 2 | throw + being-thrown |
| Ceremony | 3 | intro, win, dizzy |
| Total | ~30–32 | BKB's ~75 includes redundant variants + mirrored versions |
At 60fps with modern pacing, average clip ≈ 30–60 frames → ~1,200–1,800 unique frames per character. That's the asset bill per fighter.
Per-move metadata (one JSON per move, replaces .zon/.geo/.me2)
{
"name": "jab", "input": "LP", "damage": 30,
"startup": 5, "active": [5, 8], "recovery": 14,
"cancels": ["special", "super"], "onBlock": -2, "onHit": 3,
"rootMotion": [0, 0, 2, 4, 4, 2, 0],
"boxes": { "auto": true, "hitFrames": {"5-8": [{"bone": "handR", "r": 28}]} }
}
The one big modernization: auto-hitboxing
Run DWPose/RTMPose skeleton estimation over every rendered frame → generate per-frame capsule hurtboxes from joint positions automatically. Hand-author only the hit boxes (active frames of attacks), which is ~4 frames per attack. This deletes 95% of the 90s labor. It's also the same DWPose stack the MODELBEAST gen pipeline already uses for pose conditioning — one skeleton pass serves both generation and collision.
3. Recommended architecture for FOITIN
Asset strategy: 3D-first, rendered to digitized sprites ("3D digitized")
Instead of filming actors (BKB) or pure image-to-image chains (fragile identity), build each fighter as a textured 3D character and render the digitized look:
MODELBEAST pipeline per character:
1. FLUX + character LoRA → master identity portrait(s)
2. Hunyuan3D-2.1 / TRELLIS → textured, rigged-ready 3D mesh (GLB)
3. Auto-rig + mocap clips → the SHARED move library (30 clips, retargeted per character)
4. Fixed orthographic camera → render 60fps PNG frames + normal-map pass + depth pass
5. DWPose over renders → auto hurtbox capsules per frame
6. Pack: WebP/basis atlas + JSON → drop-in character folder
Why this beats video capture and beats pure 2D generation:
- One mocap library, every character. Retarget the same 30 clips to each new rig — a new fighter costs one mesh + one retarget + one render batch (hours on MODELBEAST, not weeks).
- Perfect frame consistency, perfect alpha (no chroma halo), free normal maps → dynamic stage lighting on sprites (the 2.5D look the tech report describes).
- The 3D source stays in the vault: cinematic camera moves for supers, restyling, re-rendering at any resolution later. Character-specific signature moves are just extra clips in that character's folder.
Engine: Godot 4.x
Matches the tech report's recommendation and our needs: deterministic fixed-tick
_physics_process, AnimatedSprite2D + normal maps + canvas shaders, exports to desktop AND
HTML5/WASM (partly.party-friendly). Combat core = finite state machine + input-buffer reading
numpad-notation motions, fixed 60Hz tick decoupled from render. Design it
deterministic-from-inputs on day one so rollback netcode stays possible.
Character folder spec (the BKB idea, modernized)
characters/<name>/
manifest.json ← display name, stats, move list, palette variants
portrait.png select.webm
moves/<move>/
frames.atlas.webp ← packed sprite frames (+ normals.webp, optional)
data.json ← frame windows, damage, boxes, root motion
audio/ ← per-move whoosh/hit/voice
source/<name>/ ← (not shipped) GLB mesh, LoRA, mocap retargets, render scenes
Engine scans characters/* at boot → roster builds itself. That is the "add characters as I
make them" requirement solved — same as BKB's per-character folders, but self-describing.
4. Effort assessment
| Phase | Work | Scale |
|---|---|---|
| 1. Combat core | FSM, input buffer, fixed tick, box collision, training-mode hitbox viewer | the hard code; small but must be exact |
| 2. Shared move library | ~30 mocap/hand-keyed clips, named vocabulary (BKB-style) | one-time cost, reused forever |
| 3. Pipeline scripts | mesh→rig→retarget→render→pose→pack, one command per character | MODELBEAST jobs |
| 4. First 2 fighters + 1 stage | proves the loop end-to-end | the real milestone |
| 5. Roster growth | new character = new mesh through the pipeline | marginal cost ≈ hours |
Verdict: very buildable. The genre's whole trick is that the engine is small and dumb while the data is rich — a 1.4MB exe ran BKB2. Our advantages over 2002: free auto-hitboxing via pose estimation, free asset generation via MODELBEAST, 60fps with no ROM limits, and a 3D source of truth the originals never had. The two things that will make or break it are feel (frame data tuning — steal MK's uniform-mechanics doctrine and modern startup timings, not BKB's) and identity consistency (solved by going through 3D rather than per-frame image generation).
Original assets only — BKB data stays as reference for formats/mechanics study, nothing ships.