import { describe, expect, it } from "vitest"; import { spectatorCameraBoosted, spectatorCameraTranslation, spectatorKeyboardAxes, spectatorKeyboardLookDelta, } from "./spectatorCameraMath"; describe("dungeon spectator free camera", () => { it("maps desktop flight controls independently from player movement state", () => { const held = new Set(["KeyW", "KeyD", "KeyE", "ShiftLeft"]); expect(spectatorKeyboardAxes(held)).toEqual({ forward: 1, right: 1, vertical: 1 }); expect(spectatorCameraBoosted(held)).toBe(true); expect(spectatorKeyboardAxes(new Set(["KeyS", "KeyA", "KeyQ"]))).toEqual({ forward: -1, right: -1, vertical: -1, }); }); it("flies along the view direction and uses world-relative vertical movement", () => { expect(spectatorCameraTranslation(0, 0, { forward: 1, right: 0, vertical: 0 }, 0.1, false)) .toEqual([0, 0, 1]); expect(spectatorCameraTranslation(0, 0, { forward: 0, right: 0, vertical: 1 }, 0.1, false)) .toEqual([0, 1, 0]); const pitched = spectatorCameraTranslation(0, Math.PI / 6, { forward: 1, right: 0, vertical: 0 }, 0.1, false); expect(pitched[1]).toBeCloseTo(0.5, 6); expect(pitched[2]).toBeCloseTo(Math.sqrt(3) / 2, 6); }); it("strafes A left and D right in screen space", () => { expect(spectatorCameraTranslation(0, 0, { forward: 0, right: 1, vertical: 0 }, 0.1, false)) .toEqual([-1, 0, 0]); expect(spectatorCameraTranslation(0, 0, { forward: 0, right: -1, vertical: 0 }, 0.1, false)) .toEqual([1, 0, 0]); }); it("turns with held arrow keys using bounded frame deltas", () => { expect(spectatorKeyboardLookDelta(new Set(["ArrowRight", "ArrowUp"]), 0.1)) .toEqual([0.225, -0.15500000000000003]); expect(spectatorKeyboardLookDelta(new Set(["ArrowLeft", "ArrowDown"]), 1)) .toEqual([-0.225, 0.15500000000000003]); expect(spectatorKeyboardLookDelta(new Set(["ArrowLeft"]), Number.NaN)).toEqual([-0, 0]); }); it("normalizes diagonal speed and clamps long render-frame gaps", () => { const diagonal = spectatorCameraTranslation(0, 0, { forward: 1, right: 1, vertical: 1 }, 1, false); expect(Math.hypot(...diagonal)).toBeCloseTo(1, 6); const boosted = spectatorCameraTranslation(0, 0, { forward: 1, right: 0, vertical: 0 }, 1, true); expect(Math.hypot(...boosted)).toBeCloseTo(2.8, 6); expect(spectatorCameraTranslation(Number.NaN, 0, { forward: 1, right: 0, vertical: 0 }, 0.1, false)) .toEqual([0, 0, 0]); }); });