Replace code-buried CPUParticles with inspector-editable effect scenes fired through one Fx autoload: code names the effect (Fx.spawn(&"blood_burst", xform)), the .tscn owns the look. Ships four placeholder effects (blood_burst, slam_dust, spark, hit_flash) seeded from the old code params, a self-freeing one_shot_effect root helper, a live preview gallery, and an FX style guide for Siim. CPUParticles only (mobile GLES3 constraint). Existing call sites untouched -- migrated later. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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
- 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. - Pick an effect
.tscninfx/(blood_burst,slam_dust,spark,hit_flash) and open it. - Tune it in the inspector. Everything lives on the
CPUParticles3Dnode 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.
- 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 |