5.0 KiB
5.0 KiB
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.