Files
Bullosseum/systems/fx/README.md
T
richard 7b6a141767 Reorganize the codebase into role-based folders (snake_case)
Move the 40-odd root-level scripts and scenes into a tree that groups by role,
per the approved roadmap (WS2/WS3): actors/{player,matador,bear}, systems/{combat,
fx,input,debug,render,crowd,config}, ui/, props/ (was tscn_s/). Rename the shell
scene.tscn -> levels/game_shell.tscn and every PascalCase scene to snake_case
(Player.tscn -> player.tscn, MainMenu.tscn -> main_menu.tscn, etc.) so the
case-insensitive web/macOS filesystems can't alias two files together.

Done as a scripted move: each file travels with its .uid; every quoted res:// path
across scenes, scripts, .tres, and project.godot's 9 autoloads is rewritten; the
.godot uid/class cache is rebuilt from scratch. Scenes still resolve by uid, so the
rewrite is belt-and-suspenders. Lint globs (run_tests.sh + both CI workflows) now
walk the new dirs; an orphan animation_tree.gd.uid and 7 pre-existing trailing-
whitespace lints (barrel/torch, never covered by the old root-only glob) are cleaned.

Full suite green on both sides. Asset consolidation (Assets/Animations/fonts ->
art/) is deferred — moving imported .glb/.png/.ttf is safer done in the editor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017KoYBYQgRyY1zDHXMsXY3V
2026-09-06 00:04:41 +03:00

3.2 KiB

FX — the effect library

Gameplay code fires a named effect; the scene decides how it looks. That split is the whole point: a programmer writes Fx.spawn(&"blood_burst", hit_transform) once, and from then on every change to how a hit feels is a .tscn Siim edits in the inspector — no code, no recompile.

# anywhere in gameplay code
Fx.spawn(&"blood_burst", global_transform)          # at a node
Fx.spawn(&"slam_dust", Transform3D(Basis(), point)) # at a world point

Siim's workflow

  1. Open the gallery. Run fx/effect_gallery.tscn. It loops through every effect on a sand-lit stage with the effect's name on screen, so you see each one the way it reads in play.
  2. Pick an effect .tscn in fx/ (blood_burst, slam_dust, spark, hit_flash) and open it.
  3. Tune it in the inspector. Everything lives on the CPUParticles3D node and its material:
    • Colour → the node's Color Ramp (start colour → faded/transparent end).
    • Shape of the burst over time → Scale Amount Curve.
    • Amount / Lifetime / Explosiveness / Spread / Velocity / Gravity → the node's emission group.
    • The viewport previews particles live as you drag — no play needed.
  4. Save. That's the whole edit. Re-run the gallery to compare.

New effect? Add a fx/<name>.tscn (root = CPUParticles3D with one_shot_effect.gd attached — copy an existing one), then register its name → path in fx/fx.gd.

House style (keep effects reading as one game)

Palette — pull from these, don't invent per-effect colours:

Role Start End (fades to alpha 0)
Blood #FF0505 #400000
Dust #B89966 (tan) #8C7326
Ember #FFF299 → #FF8C1A transparent
Flash #FFFFFF transparent

Timing budgets — hits read best short: strike/flash effects ≤ 0.4 s, dust/settle ≤ 1.1 s. A one-shot effect frees itself lifetime + 0.5 s after spawn (one_shot_effect.gd), so keep lifetime honest.

PS1 look — materials are unshaded, alpha-blended, vertex-colour (colour comes from the ramp), cull disabled. Prefer few, chunky, low-poly billboarded quads over dense fine particles; the game runs the PS1 filter over everything, so subtlety is lost anyway.

Mobile — effects are CPUParticles3D, never GPUParticles3D. The web/GLES3/ANGLE target compiles particle shaders badly (see the notes in player.gd); CPU particles are just as tunable in the inspector and safe on-device. Keep this constraint when adding effects.

Files

File What it is
fx.gd The Fx autoload — spawn(name, xform, parent=null); name→path registry
one_shot_effect.gd Root helper: fires the emitter(s) once, frees the scene when done
blood_burst.tscn etc. The effects themselves — edit these
effect_gallery.tscn Preview stage (run it to review)
_seed_placeholders.gd One-off generator that wrote the first-draft defaults; not used at runtime