orbit/js/combat/CamShake.js

43 lines
1.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { config } from '../config/Config.js';
import { ensureUiCameras, assignWorld, assignUi } from '../visuals/UiCameras.js';
export { ensureUiCameras, assignWorld, assignUi };
/**
* The combat CAMERA KICK — a subtle world-camera shake on the big beats:
* you taking a hit, a hostile going down, the shield collapse.
*
* It fires on the WORLD camera only. The UI pass (js/visuals/UiCameras.js
* → `fx-ui`) renders the bar, feed, and gauge flashes on its own fixed
* pass, so the HUD stays perfectly still while the world kicks — that's
* the whole point of the split. Call `ensureUiCameras(scene)` at scene
* setup (both combat contexts do) so the split exists when the shake
* lands; without a split (a scene without cameras, the headless tests)
* this is a guarded no-op.
*
* Tuning: data/combat.json → combat.fx.shake — `hit` / `kill` / `break`
* are the Phaser shake intensities (a small FRACTION of the viewport,
* the same idiom as the tether contact's 0.003–0.007 in GameScene), and
* `ms` is the duration.
*/
/**
* @param {object} scene the combat scene
* @param {string} kind 'hit' | 'kill' | 'break' — the fx.shake.* intensity
* to use (the beat's weight: a player hit < an enemy kill < the
* shield-collapse)
*/
export function combatShake(scene, kind = 'hit') {
const cam = scene?.cameras?.main;
if (!cam || typeof cam.shake !== 'function') return;
const fallback = { hit: 0.0045, kill: 0.007, break: 0.011 }[kind] ?? 0.005;
const intensity = Number(config.get(`combat.fx.shake.${kind}`, fallback));
if (!Number.isFinite(intensity) || intensity <= 0) return;
const ms = Math.max(60, Number(config.get('combat.fx.shake.ms', 230)) || 230);
// The UI split (once) so the kick hits the WORLD pass only — the bar,
// feed, and gauge flashes render on the untouched `fx-ui` pass and stay
// perfectly still. (Idempotent; null-safe for camera-less scenes.)
ensureUiCameras(scene);
cam.shake(ms, intensity);
}