A satirical political 2D fighting game for Godot 4.3+ (developed against 4.6.3). Classic 6-button Street Fighter rules, data-driven roster of 22, eight dynamic stages, and GGPO-style rollback — not delay-based netcode.
Primary targets: macOS, iOS, iPadOS. Keyboard, Xbox, DualShock 4 / DualSense, and touch.
- Install Godot 4.3+ (4.4 / 4.6 are fine).
- Import
SuperPACOut/as a project, or from a terminal:
godot --path SuperPACOutHeadless test runners (these call the shipped sim, not a reimplementation):
godot --headless --path SuperPACOut --script res://tests/run_combat_tests.gd
godot --headless --path SuperPACOut --script res://tests/run_rollback_tests.gd
godot --headless --path SuperPACOut --script res://tests/run_match_harness.gd| P1 | P2 | Xbox | PlayStation | |
|---|---|---|---|---|
| Move | WASD | Arrows | D-pad / LS | D-pad / LS |
| LP MP HP | U I O | Numpad 4 5 6 | X Y RB | Square Triangle R1 |
| LK MK HK | J K L | Numpad 1 2 3 | A B RT | Cross Circle R2 |
| 4-button L M H S | U I O P | 4 5 6 0 | X Y RB LB | Square Triangle R1 L1 |
Remap everything in Settings. Mobile uses the on-screen 4-button pad (L/M/H + Special).
Combat is a pure function of (state, p1_input, p2_input) -> state inside
scripts/combat/match_sim.gd. Godot’s variable physics is not used for hit detection.
Presentation (sprites, HUD, audio) ← read only
▲
MatchScene._process (renders last tick)
▲
RollbackManager.simulate_step()
▲
MatchSim.tick() 60 Hz, integers only
- Simulation lives in
MatchSim(RefCounted). State is one dictionary, saved every frame. - Rollback (
scripts/netcode/rollback_manager.gd) predicts remote input by carrying the last confirmed bits. A late / mismatched packet loads the pre-tick snapshot and resimulates forward. Checksums detect desyncs. - Input delay defaults to 2 frames.
local_side_delayis always 0 — the local player does not eat an extra delay on top of the configured delay. - Local versus and fake-online both call the same
simulate_step()→MatchSim.tick(). - Transport is a P2P stub (
TransportStub) with an optional relay flag. Ranked / unranked / lobby are stubs.
Units are centipixels (1/100 px). No floats in the tick.
res://
├── assets/{characters,stages,vfx,ui,audio} # placeholders + drop-in art
├── data/{characters,stages} # JSON movesets / stages
├── scenes/{characters,stages,ui,main}
├── scripts/{combat,netcode,characters,stages,input,systems}
├── autoload/ # Game, Roster
└── tests/ # shipped-API runners
- Copy
data/characters/barack_obama.jsontodata/characters/<id>.json. - Set
id,display_name,short_name,side,archetype,color,initials. - Tune
stats. Keep the normal keys (5LP…jHK). Add 2–3specials(motion + button + frame data) and onesuperwithmeter_cost: 10000. - Add
throw,win_pose, and at least onewin_quotesentry. - Append the id to
data/roster.jsonand toCharacterDB.required_named_ids()if you want the roster test to cover it. - Drop placeholders at
assets/characters/<id>/idle_000.png(andportrait.png).
Motions the detector understands: qcf, qcb, dp, hcf, hcb, charge_b, charge_d.
Buttons: P, K, LP/MP/HP/LK/MK/HK, PP, KK.
No GDScript changes are required for a data-only fighter.
Art is never hardcoded. Presentation looks up:
assets/characters/<id>/<anim>_000.png
assets/characters/<id>/portrait.png
assets/characters/<id>/win_screen.png
assets/stages/<id>/<layer>.png
assets/vfx/<name>_000.png
assets/ui/<name>.png
If the file is missing, you get a colored rectangle + initials. If it exists, it is used.
- Open
ASSET_GENERATION_MANIFEST.md. - Copy the prompt under the path you want (every prompt starts with the style lock).
- Generate in Grok Imagine. Save over that exact path (add
_001,_002… for extra frames). - Reload the project. Zero code changes.
Every stage JSON lists at least one match-state-driven dynamic:
| id | name | dynamic |
|---|---|---|
white_house |
White House Rose Garden | destructible bushes + Secret Service at low health |
capitol_steps |
US Capitol Steps | crowd meter feeds super + round-3 debris |
x_hq |
X (Twitter) HQ | live ticker from who is winning |
wall_street |
Wall Street / NYSE | market-crash hazard at low health |
southern_border |
Southern Border Crossing | wall hazard on super |
silicon_valley |
Silicon Valley Tech Campus | weather/heat from round number |
debate_stage |
Presidential Debate Stage | audience meter feeds super; podiums as platforms |
mar_a_lago |
Mar-a-Lago | chandelier on super + destructible gold |
export_presets.cfg ships macOS, iOS, and iPadOS (iOS platform, targeted_device_family=2) presets. Fill in your team id / provisioning before shipping.
Fighters are satirical cartoon archetypes, not likeness-licensed portraits. Placeholder art is geometric on purpose. Final sprites should stay caricature, not photo-real.