Back to Poly Dogfight
SOURCE / PINNED RELEASE

Made of little things.

Poly Dogfight

Release
b8511ee374e3…
Author-recorded commit
5579434b9d8b…
License
LICENSE
Author’s source reference
nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.napplet.soy%2F/n-44f63e5422b

Archive hash verified: bcadd2430d8ea2bc…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

tests/horizon.test.mjs
// Horizon culling and the terrain early-out. Node strips the TypeScript types.
import test from 'node:test';
import assert from 'node:assert/strict';
import { BufferAttribute, BufferGeometry, Object3D, Vector3 } from 'three';
import { createHorizonCuller, splitIntoChunks, CHUNK_DIRECTIONS } from '../src/world/chunks.ts';
import { PLANET_RADIUS } from '../src/sim/constants.ts';
import { underSurface } from '../src/sim/flight.ts';

/** A small triangle patch around `dir` (degrees off the north pole toward +x) at radius r. */
function patch(degrees, r = PLANET_RADIUS + 1) {
  const a = (degrees * Math.PI) / 180;
  const at = (da, side) => new Vector3(Math.sin(a + da), Math.cos(a + da), side).normalize().multiplyScalar(r);
  const points = [at(-0.01, -0.01), at(0.01, -0.01), at(0, 0.01)];
  const geometry = new BufferGeometry();
  geometry.setAttribute('position', new BufferAttribute(new Float32Array(points.flatMap((p) => [p.x, p.y, p.z])), 3));
  return geometry;
}

test('horizon culler hides what the planet hides and keeps what pokes above the horizon', () => {
  const culler = createHorizonCuller();
  const objects = {};
  const cases = { below: [0], nearHorizon: [25], pastHorizon: [60], farSide: [180], tallPastHorizon: [60, PLANET_RADIUS + 150] };
  for (const [name, [deg, r]] of Object.entries(cases)) {
    objects[name] = new Object3D();
    culler.add(objects[name], patch(deg, r));
  }
  // 50 m up over the pole: the sea-level horizon is ~24° of arc away.
  culler.cullFor(new Vector3(0, PLANET_RADIUS + 50, 0));
  assert.equal(objects.below.visible, true);
  assert.equal(objects.nearHorizon.visible, true);
  assert.equal(objects.pastHorizon.visible, false);
  assert.equal(objects.farSide.visible, false);
  assert.equal(objects.tallPastHorizon.visible, true);
  // From far out in orbit most of the near hemisphere shows.
  culler.cullFor(new Vector3(0, PLANET_RADIUS * 3.2, 0));
  assert.equal(objects.pastHorizon.visible, true);
  assert.equal(objects.farSide.visible, false);
});

test('chunk split keeps every triangle and drops the ones filtered out', () => {
  const geometry = new BufferGeometry();
  const tris = CHUNK_DIRECTIONS.flatMap((d) => [d.x, d.y, d.z, d.x + 0.01, d.y, d.z, d.x, d.y + 0.01, d.z]);
  geometry.setAttribute('position', new BufferAttribute(new Float32Array(tris), 3));
  const all = splitIntoChunks(geometry);
  assert.equal(all.size, CHUNK_DIRECTIONS.length);
  const half = splitIntoChunks(geometry, (first) => first % 6 === 0);
  const kept = [...half.values()].reduce((n, g) => n + g.getAttribute('position').count / 3, 0);
  assert.equal(kept, CHUNK_DIRECTIONS.length / 2);
});

test('underSurface skips the terrain lookup above the highest ground', () => {
  let lookups = 0;
  const world = { surfaceHeight: () => (lookups++, 40), terrainHeight: () => 40, hitsObstacle: () => false, maxSurfaceHeight: 50 };
  assert.equal(underSurface(world, new Vector3(0, PLANET_RADIUS + 80, 0)), false);
  assert.equal(lookups, 0);
  assert.equal(underSurface(world, new Vector3(0, PLANET_RADIUS + 30, 0)), true);
  assert.equal(underSurface(world, new Vector3(0, PLANET_RADIUS + 45, 0)), false);
  assert.equal(lookups, 2);
});

test('castRay stops at the ground or an obstacle and otherwise reaches its range', async () => {
  const { castRay } = await import('../src/sim/aim.ts');
  const flat = { surfaceHeight: () => 0, terrainHeight: () => 0, hitsObstacle: () => false, maxSurfaceHeight: 10 };
  const from = new Vector3(0, PLANET_RADIUS + 40, 0);
  // Straight down: meets the ground about 40 m below.
  assert.ok(Math.abs(castRay(from, new Vector3(0, -1, 0), 150, flat) - 40) <= 2);
  // Level flight over flat ground stays clear for 150 m.
  assert.equal(castRay(from, new Vector3(1, 0, 0), 150, flat), 150);
  // A wall 60 m ahead.
  const wall = { ...flat, hitsObstacle: (p) => p.x > 60 };
  assert.ok(Math.abs(castRay(from, new Vector3(1, 0, 0), 150, wall) - 60) <= 2);
});