import { describe, expect, it } from 'vitest'; import { HERO_CAR_HALF_WIDTH, TRAFFIC_BODY, TRAFFIC_FADE_LENGTH, TRAFFIC_LANE_JITTER, TRAFFIC_LANES, TRAFFIC_NEAR_Z, trafficLamps, trafficNearFade, wrapTrafficZ, } from '@/scene/world/traffic'; describe('expressway traffic stays clear of the hero car', () => { it('keeps every body outside the hero car, with lane jitter', () => { for (const lane of TRAFFIC_LANES) { const inner = Math.abs(lane.x) - TRAFFIC_BODY[lane.kind].halfWidth - TRAFFIC_LANE_JITTER; expect(inner).toBeGreaterThan(HERO_CAR_HALF_WIDTH); } }); it('never lets bodies in adjacent lanes overlap, and keeps them on the road', () => { const spans = TRAFFIC_LANES.map((lane) => { const half = TRAFFIC_BODY[lane.kind].halfWidth + TRAFFIC_LANE_JITTER; return [lane.x - half, lane.x + half] as const; }).sort((a, b) => a[0] - b[0]); for (let i = 1; i < spans.length; i++) expect(spans[i]![0]).toBeGreaterThan(spans[i - 1]![1]); for (const [left, right] of spans) { expect(left).toBeGreaterThan(-8); expect(right).toBeLessThan(8); } }); it('runs each lane at one speed, so no vehicle drives through another', () => { const xs = TRAFFIC_LANES.map((lane) => lane.x); expect(new Set(xs).size).toBe(xs.length); }); it('puts every lamp on the vehicle body', () => { for (const kind of ['car', 'truck'] as const) { const lamps = trafficLamps(kind, 0.5); expect(lamps.length).toBeGreaterThanOrEqual(3); for (const lamp of lamps) expect(Math.abs(lamp.x) + lamp.w / 2).toBeLessThanOrEqual(TRAFFIC_BODY[kind].halfWidth + 0.01); } // A readable pair: two tail lamps mirrored at one height. const [left, right] = trafficLamps('car', 0); expect(left!.x).toBe(-right!.x); expect(left!.y).toBe(right!.y); }); it('is fully dark before the car near field and lit beyond the fade', () => { expect(trafficNearFade(TRAFFIC_NEAR_Z)).toBe(0); expect(trafficNearFade(0)).toBe(0); expect(trafficNearFade(40)).toBe(0); expect(trafficNearFade(TRAFFIC_NEAR_Z - TRAFFIC_FADE_LENGTH)).toBe(1); expect(trafficNearFade(-300)).toBe(1); // The car's nose is at about z = -5.5: the near field starts well ahead. expect(TRAFFIC_NEAR_Z).toBeLessThan(-18); }); it('wraps vehicles inside the hidden band at any scroll speed', () => { // 110 units/s at a 0.1 s frame clamp is 11 units per step; test far more. for (const step of [0.5, 11, 64, 900, -11, -900]) { let z = -200; for (let i = 0; i < 400; i++) { z = wrapTrafficZ(z + step); expect(z).toBeLessThanOrEqual(TRAFFIC_NEAR_Z); expect(z).toBeGreaterThanOrEqual(-660); } } }); });