83 lines
5.0 KiB
Markdown
83 lines
5.0 KiB
Markdown
# Combat feedback — baseline audit (goal: make combat feel and read)
|
||
|
||
Scope: range = `combat.html` / `/combat` (js/combat/CombatScene.js), main game = `index.html?combat`
|
||
(js/scenes/GameScene.js + js/combat/CombatSystem.js + js/ui/CombatBar.js). Shared: js/combat/{Combat,
|
||
EnemyShip,Bullet,Fx}.js, data/combat.json.
|
||
|
||
## What EXISTS today
|
||
|
||
### VFX (both contexts, shared Fx.js: additive soft-dot flashes/rings/sparks, world-space, stepped in update)
|
||
- Player shot: muzzle flash (range 30 px / main 26 px, 110 ms)
|
||
- Enemy shot: muzzle flash (28 px, 100 ms)
|
||
- Bullet impact: pink flash on enemy hits, blue on player hits (130 ms)
|
||
- Player hit: generic white flash on the ship (60 px, 140 ms) — NOT distinct shield vs hull
|
||
- Enemy kill: `Fx.explode` (white core + color bloom + ring + 22 sparks)
|
||
- Player down: `Fx.explode` + range-only "SIGNAL LOST" center message (main game: no message)
|
||
- Player respawn: cyan flash
|
||
- Ram: white flash at contact midpoint
|
||
- Thrust glow dot (range only)
|
||
|
||
### SFX
|
||
- **Zero combat SFX in both contexts.**
|
||
- Range loads NO audio at all (CombatScene.preload = textures only) → range SFX needs a load step.
|
||
- Main game loads all 17 files from data/sfx.json in GameScene.preload.
|
||
- Shared voice exists: `playSfxOn(scene, name)` / `playSfxOneOfOn` (js/utils/Sfx.js) with guards
|
||
(sfx.enabled, sound manager, audio-cache check). No combat keys in data/sfx.json yet.
|
||
- Repurposable existing files (no new binaries): scan-01 (ping), ui_click/ui_hover (ticks),
|
||
ui_window (whoosh), mining-02 (crack), thunder-01..04 (boom set), type-construct (build-up),
|
||
type-deconstruct (collapse).
|
||
|
||
### Readability / UI
|
||
- Range HUD: top-left armor panel (HULL/SHD bars + numbers), top-right KILLS counter, center
|
||
message. **No damage numbers, no kill feed, no target indicator, no bar hit-flash, no threat cues.**
|
||
- CombatBar (main game): vertical SHD/HUL gauges (fill = level, updated each frame via setStats),
|
||
8 empty skill seats (cast() stub), ENR gauge (static full). **No hit-flash, no numeric readout,
|
||
no feed, no target read.**
|
||
- CombatSystem hooks: onPlayerDamage / onPlayerDown / onPlayerUp / onKill / onActiveChange —
|
||
GameScene wires ONLY onActiveChange (bar swap). The other four are available seams (currently null).
|
||
- Range has NO hooks at all — its damage/kill/down paths live inline in CombatScene.
|
||
|
||
### Ship handling
|
||
- Range (WASD): CombatScene.updatePlayer applies combat.player rotSpeed 4.8 rad/s (instant rate cap),
|
||
thrust 1500 px/s², brake 0.6×thrust (S/Down), maxSpeed 560 cap. **Drag: combat.player.drag 1.6 is
|
||
DEAD CONFIG — not read anywhere; effective drag is ship.drag 2.4 from data/ship.json via Ship.update.**
|
||
- Main game: click-to-fly (Ship.js: ship.json thrust 900, maxSpeed 480, drag 2.4, rotSpeed 10) —
|
||
mouse steers, combat adds auto-fire only. WASD not used there.
|
||
- No throttle ramp, no rotation smoothing — both feel instant/steppy (candidate micro-feel gaps).
|
||
|
||
### Duplication (parity risk)
|
||
- fire/kill/respawn/damagePlayer logic is COPIED between CombatScene and CombatSystem (each has its
|
||
own fx.flash calls, its own armor bookkeeping, its own respawn timers). Fx.js itself is shared.
|
||
- SFX wiring must go into BOTH copy sites (or a shared helper) to stay in sync.
|
||
|
||
## Gaps vs success criteria (per feedback type)
|
||
|
||
| Event | Range VFX | Main VFX | SFX (both) | Notes |
|
||
|---|---|---|---|---|
|
||
| Firing (player) | muzzle flash | muzzle flash | none | distinct sound needed |
|
||
| Firing (enemy) | muzzle flash | muzzle flash | none | (nice-to-have, distinct + quieter) |
|
||
| Bullet impact (enemy hit) | flash | flash | none | no damage number |
|
||
| Shield hit (player) | generic flash | generic flash | none | not distinct from hull hit |
|
||
| Hull hit (player) | generic flash | generic flash | none | not distinct; bar doesn't flash |
|
||
| Enemy kill | explode | explode | none | no kill feed |
|
||
| Player down | explode + msg | explode only | none | main game gives no down cue |
|
||
| Player respawn | flash | flash | none | none distinct |
|
||
|
||
| Readability item | Range | Main |
|
||
|---|---|---|
|
||
| Damage numbers (both sides) | missing | missing |
|
||
| Target/lock indicator | missing | missing (auto-fire target invisible) |
|
||
| Threat cues (hostile state) | missing | missing |
|
||
| Kill feed | KILLS counter only | missing |
|
||
| Bar hit-flash (SHD/HUL) | N/A (own HUD panel) | missing |
|
||
|
||
## Ground rules found in code (must keep)
|
||
- Pure rules in js/combat/Combat.js, tested by dev/combat.test.mjs (344 lines; stubs Phaser;
|
||
covers applyDamage/headingOf/orbitStep/EnemyShip/Bullet/CombatSystem incl. auto-fire, swept hits,
|
||
rams, respawn, cast-stub). New pure feel rules belong there + tested.
|
||
- Fx items are world-space additive dots; combat scene steps fx.update(delta) in its loop.
|
||
- No arcade colliders; swept circle checks (hitsSwept) in both contexts.
|
||
- All numbers in data/combat.json; CombatBar built like ActionBar (scene.add.* + container parenting).
|
||
- data/sfx.json key = play name, asset queued `sfx_<key>`; sfx.enabled master switch.
|
||
- Theme palette: neon #00e5ff, neon2 #ff2d6f, amber #ffc94d, ink #eaf6ff, dim #7d92c4, faint #3d4c74.
|