import { BoxGeometry, Mesh, MeshBasicMaterial, Raycaster, Vector3 } from "three"; import { describe, expect, it } from "vitest"; import { arenaCameraClearDistance, arenaCameraPose, arenaSpawnYaw, ARENA_CAMERA_DISTANCE } from "./arenaCamera"; import { ARENA_STAGES } from "./arenaStages"; describe("arena player camera", () => { it("starts behind each character at the playable floor on all eight maps", () => { for (const stage of ARENA_STAGES) { for (const team of [0, 1] as const) { const foot = stage.teamSpawns[team]; const { position, target } = arenaCameraPose(foot, arenaSpawnYaw(stage, team)); expect(target[0]).toBe(foot[0]); expect(target[2]).toBe(foot[2]); expect(target[1] - foot[1]).toBeCloseTo(1.35); expect(new Vector3(...position).distanceTo(new Vector3(...target))).toBeCloseTo(ARENA_CAMERA_DISTANCE); expect(position[1] - foot[1]).toBeLessThan(4); } } }); it("follows player translation and responds to orbit input", () => { const first = arenaCameraPose([1, -22, 3], 0); const moved = arenaCameraPose([11, -20, 5], 0); expect(moved.position.map((value, axis) => value - first.position[axis])).toEqual([10, 2, 2]); expect(arenaCameraPose([1, -22, 3], Math.PI / 2).position).not.toEqual(first.position); expect(arenaCameraPose([0, 0, 0], NaN, Infinity).position.every(Number.isFinite)).toBe(true); }); it("pulls in before a wall and restores full distance in open space", () => { const wall = new Mesh(new BoxGeometry(8, 8, 0.2), new MeshBasicMaterial()); wall.position.set(0, 1.5, -2); wall.updateMatrixWorld(true); const target = new Vector3(0, 1.5, 0); const ray = new Raycaster(); expect(arenaCameraClearDistance(target, new Vector3(0, 1.5, -6), wall, ray)).toBeCloseTo(1.7); expect(arenaCameraClearDistance(target, new Vector3(6, 1.5, 0), wall, ray)).toBe(6); wall.geometry.dispose(); wall.material.dispose(); }); });