Newer
Older
rpg / packages / engine / src / render / __tests__ / shadowSim.test.ts
import { describe, expect, it } from 'vitest';
import { blobPlacement, sunShadow } from '../shadowSim';

describe('sunShadow', () => {
    it('ночью тени нет', () => {
        expect(sunShadow(2)).toBeNull();
        expect(sunShadow(23)).toBeNull();
        expect(sunShadow(5.5)).toBeNull();
    });

    it('на границах дня альфа нулевая, в разгар дня максимальная', () => {
        expect(sunShadow(6)!.alpha).toBeCloseTo(0);
        expect(sunShadow(19.9)!.alpha).toBeCloseTo(0); // к закату гаснет (в 20 — null)
        const noon = sunShadow(13)!.alpha;
        expect(noon).toBeGreaterThan(0.3);
        const morning = sunShadow(7)!.alpha; // ещё в разгоне (dawn..day = 6..8)
        expect(morning).toBeGreaterThan(0);
        expect(morning).toBeLessThan(noon);
    });

    it('тень утром на запад экрана, вечером на восток', () => {
        expect(sunShadow(7)!.dirX).toBeLessThan(-0.5);
        expect(sunShadow(19)!.dirX).toBeGreaterThan(0.5);
        expect(sunShadow(13)!.dirX).toBeCloseTo(0); // полдень — почти под объектом
    });

    it('длина максимальна утром/вечером, минимальна в полдень', () => {
        const noon = sunShadow(13)!.len;
        const morning = sunShadow(7)!.len;
        const evening = sunShadow(19)!.len;
        expect(noon).toBeLessThan(morning);
        expect(noon).toBeLessThan(evening);
        expect(morning).toBeCloseTo(evening, 1); // симметричный день
    });

    it('вектор направления единичный', () => {
        for (let h = 6; h < 20; h += 0.5) {
            const s = sunShadow(h)!;
            expect(Math.hypot(s.dirX, s.dirY)).toBeCloseTo(1);
        }
    });
});

describe('blobPlacement', () => {
    it('эллипс тянется от базы вдоль направления тени', () => {
        const sun = { dirX: 1, dirY: 0, len: 1, alpha: 0.3 };
        const b = blobPlacement(10, 40, sun);
        expect(b.x).toBeCloseTo((40 + 8) / 2); // reach = height·len
        expect(b.y).toBe(0);
        expect(b.scaleX).toBeCloseTo(24);
        expect(b.scaleY).toBeCloseTo(10); // 0.7 + 0.3·len = 1.0 при len=1
        expect(b.alpha).toBeCloseTo(0.3);
        expect(b.rotation).toBeCloseTo(0);
    });

    it('длинная утренняя тень дальше, чем короткая полуденная', () => {
        const morning = blobPlacement(10, 40, { dirX: -1, dirY: 0, len: 1.5, alpha: 0.3 });
        const noon = blobPlacement(10, 40, { dirX: 0, dirY: 1, len: 0.6, alpha: 0.3 });
        expect(Math.hypot(morning.x, morning.y)).toBeGreaterThan(Math.hypot(noon.x, noon.y));
    });

    it('поворот соответствует направлению тени', () => {
        const b = blobPlacement(10, 40, { dirX: 0, dirY: 1, len: 1, alpha: 0.3 });
        expect(b.rotation).toBeCloseTo(Math.PI / 2);
    });
});