c0a022fed4
An Fx autoload + one_shot_effect base so every effect is an inspector-editable .tscn (the systems/fx/ authoring dir): blood/slam/spark/flash primitives and the bull's kick/dash/slam/roll + movement effects (bull_*.tscn), fired via Fx.spawn() / Fx.attach(). Plus a preview gallery + smoke test, and bull_impact_fx.gd for the coded, non-particle slam rings + kick flash-pop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CCyaJPTHCH9EDthpf4A5Sj
89 lines
5.0 KiB
Markdown
89 lines
5.0 KiB
Markdown
# 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.
|
|
|
|
```gdscript
|
|
# anywhere in gameplay code
|
|
Fx.spawn(&"blood_burst", global_transform) # one-shot: fire and forget (self-frees)
|
|
Fx.spawn(&"slam_dust", Transform3D(Basis(), point)) # at a world point
|
|
var trail := Fx.attach(&"bull_charge_trail", node) # continuous: caller keeps it + toggles .emitting
|
|
```
|
|
|
|
## 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`.
|
|
|
|
## Bull ability effects
|
|
|
|
The bull's moves are wired to effect scenes here, so **you can retune every one in the inspector** —
|
|
open the `.tscn`, drag its colour ramp / curves / emission, save. No code.
|
|
|
|
| Ability | Effect scene(s) | Kind |
|
|
|---|---|---|
|
|
| Ground slam | `bull_slam.tscn` (dust) | one-shot burst |
|
|
| Back-kick | `bull_kick.tscn` — dust **+** its `stones` and `sparks` child emitters | one-shot burst |
|
|
| Dash / roll launch | `bull_dash.tscn` | one-shot burst |
|
|
| Hoof dust (walking / sprinting) | `bull_hoof_dust.tscn` | continuous |
|
|
| Charge trail (the blue streak) | `bull_charge_trail.tscn` | continuous |
|
|
| Roll sparks | `bull_roll_sparks.tscn` | continuous |
|
|
|
|
**Two kinds, edited the same way.** *One-shot* effects fire once and clean themselves up — they show
|
|
up in the gallery, so preview and tune them there. *Continuous* effects follow the bull and switch on
|
|
and off with what it's doing (dust while moving, the trail during a roll); the gallery can't show
|
|
those, so preview one by opening its `.tscn` and ticking **Emitting** on in the inspector's viewport.
|
|
|
|
Two things stay in code and aren't yours to tune here: the slam's expanding shockwave **rings** and the
|
|
kick's white **flash-pop** — those are stretched flat meshes, not particles (`actors/player/bull_impact_fx.gd`).
|
|
The dust's *walk-vs-sprint size* is also code (a fixed multiplier); its colour and shape are the `.tscn`.
|
|
|
|
**Composite effect** (like the kick): one scene, several `CPUParticles3D` — a root plus child emitters.
|
|
`one_shot_effect.gd` fires every emitter in the scene together, so you can build a layered hit
|
|
(dust + debris + sparks) as one file and tune each layer separately.
|
|
|
|
## 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()` (one-shot) / `attach()` (continuous); name→path registry |
|
|
| `one_shot_effect.gd` | Root helper: fires every emitter in the scene once, frees it when done |
|
|
| `blood_burst.tscn` etc. | The effects themselves — **edit these** |
|
|
| `bull_*.tscn` | The bull's ability effects (see the table above) — **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 |
|