import { describe, it, expect } from 'vitest';
import { Container } from 'pixi.js';
import { Camera } from '../Camera';
import { screenToWorld, worldToScreen } from '../../math/iso';
/** Смещение цели от центра камеры в экранных пикселях: мировая точка. */
function targetAtScreenOffset(cam: Camera, dxPx: number, dyPx: number): { x: number; y: number } {
const c = worldToScreen(cam.x, cam.y);
return screenToWorld(c.x + dxPx, c.y + dyPx);
}
describe('Camera dead zone', () => {
it('без dead zone — камера центрируется на цели', () => {
const cam = new Camera(480, 270);
cam.follow(3, 5);
expect(cam.x).toBe(3);
expect(cam.y).toBe(5);
});
it('цель внутри окна — камера стоит', () => {
const cam = new Camera(480, 270);
cam.snap(3, 5);
cam.deadZonePx = { width: 160, height: 100 };
// Цель на 60 px правее и 30 px ниже центра экрана — внутри окна.
const t = targetAtScreenOffset(cam, 60, 30);
cam.follow(t.x, t.y);
expect(cam.x).toBe(3);
expect(cam.y).toBe(5);
});
it('цель толкает камеру ровно на величину выхода', () => {
const cam = new Camera(480, 270);
cam.snap(3, 5);
cam.deadZonePx = { width: 160, height: 100 };
// Выход за окно: 20 px вправо и 20 px вверх.
const t = targetAtScreenOffset(cam, 100, -70);
cam.follow(t.x, t.y);
// Центр проекции сместился ровно на (20, −20) экранных пикселей.
const c0 = worldToScreen(3, 5);
const c = worldToScreen(cam.x, cam.y);
expect(c.x - c0.x).toBeCloseTo(20, 6);
expect(c.y - c0.y).toBeCloseTo(-20, 6);
});
it('snap ставит камеру на точку, минуя окно', () => {
const cam = new Camera(480, 270);
cam.deadZonePx = { width: 160, height: 100 };
cam.snap(5, 2);
expect(cam.x).toBe(5);
expect(cam.y).toBe(2);
// Окно сохранено: цель чуть правее центра — камера не сдвигается.
const t = targetAtScreenOffset(cam, 50, 0);
cam.follow(t.x, t.y);
expect(cam.x).toBe(5);
});
});
describe('Camera bounds (мировые юниты)', () => {
it('границы мира держат камеру прижатой', () => {
const cam = new Camera(480, 270);
cam.bounds = { x: 0, y: 0, width: 64, height: 64 };
cam.snap(-1000, 500); // за границей по обеим осям
// bbox карты: x = (0 - 64)*16, y = 0; клэмп по проекции центра.
const c = worldToScreen(cam.x, cam.y);
expect(c.x).toBeCloseTo(-1024 + 240, 6);
expect(c.y).toBeCloseTo(135, 6);
});
it('apply ставит worldRoot по округлённой проекции', () => {
const cam = new Camera(480, 270);
cam.snap(3, 5);
const view = new Container();
cam.apply(view);
const applied = worldToScreen(cam.x, cam.y);
expect(view.x).toBe(240 - Math.round(applied.x));
expect(view.y).toBe(135 - Math.round(applied.y));
});
});