- 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>
164 lines
8.5 KiB
Markdown
164 lines
8.5 KiB
Markdown
# 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), jab `handa` (53f), punches `handa-e`,
|
||
kicks `kicka-…`, specials `spec1/2`, blocks, ducks, hit reactions (`bhit`, `lhit`, `bfall`,
|
||
`bkfal`…), throws, wins. ~202MB/character.
|
||
- `handa.zon`: magic `BKB!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`: magic `BKB!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):**
|
||
1. Character = folder of clips + frame-indexed metadata. Adding a fighter = adding data, zero code.
|
||
2. Frame-indexed everything: collision, root motion, damage windows all keyed to video frame N.
|
||
3. 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)
|
||
|
||
```json
|
||
{
|
||
"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.*
|