59 lines
2.9 KiB
TypeScript
59 lines
2.9 KiB
TypeScript
import RAPIER from "@dimforge/rapier3d-compat";
|
|
import { beforeAll, describe, expect, it } from "vitest";
|
|
import { DUNGEON_PHYSICAL_COLLISION_GROUPS, DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS } from "./dungeonLineOfSight";
|
|
import { hasDungeonLabelLineOfSight } from "./dungeonLabelVisibility";
|
|
|
|
beforeAll(async () => { await RAPIER.init(); });
|
|
|
|
const CAMERA = { x: 0, y: 2, z: 0 };
|
|
const LABEL = { x: 4, y: 2, z: 0 };
|
|
|
|
describe("dungeon label occlusion", () => {
|
|
it("hides labels behind solid dungeon walls using the physical spatial index", () => {
|
|
const world = new RAPIER.World({ x: 0, y: 0, z: 0 });
|
|
try {
|
|
world.createCollider(RAPIER.ColliderDesc.cuboid(0.1, 3, 3)
|
|
.setTranslation(2, 2, 0).setCollisionGroups(DUNGEON_PHYSICAL_COLLISION_GROUPS));
|
|
world.step();
|
|
expect(hasDungeonLabelLineOfSight(RAPIER, world, CAMERA, LABEL)).toBe(false);
|
|
expect(hasDungeonLabelLineOfSight(RAPIER, world, CAMERA, { x: 1, y: 2, z: 0 })).toBe(true);
|
|
} finally { world.free(); }
|
|
});
|
|
|
|
it("occludes across floors and ceilings at the exact camera and label heights", () => {
|
|
const world = new RAPIER.World({ x: 0, y: 0, z: 0 });
|
|
try {
|
|
world.createCollider(RAPIER.ColliderDesc.cuboid(5, 0.1, 5)
|
|
.setTranslation(0, 1, 0).setCollisionGroups(DUNGEON_PHYSICAL_COLLISION_GROUPS));
|
|
world.step();
|
|
expect(hasDungeonLabelLineOfSight(RAPIER, world, CAMERA, { x: 0, y: 0, z: 0 })).toBe(false);
|
|
expect(hasDungeonLabelLineOfSight(RAPIER, world, CAMERA, LABEL)).toBe(true);
|
|
} finally { world.free(); }
|
|
});
|
|
|
|
it("ignores actors, trigger volumes, and the duplicate combat sight layer", () => {
|
|
const world = new RAPIER.World({ x: 0, y: 0, z: 0 });
|
|
try {
|
|
const actor = world.createRigidBody(RAPIER.RigidBodyDesc.kinematicPositionBased());
|
|
world.createCollider(RAPIER.ColliderDesc.cuboid(0.1, 3, 3).setTranslation(1, 2, 0), actor);
|
|
world.createCollider(RAPIER.ColliderDesc.cuboid(0.1, 3, 3).setTranslation(2, 2, 0)
|
|
.setSensor(true).setCollisionGroups(DUNGEON_PHYSICAL_COLLISION_GROUPS));
|
|
world.createCollider(RAPIER.ColliderDesc.cuboid(0.1, 3, 3).setTranslation(3, 2, 0)
|
|
.setSensor(true).setCollisionGroups(DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS));
|
|
world.step();
|
|
expect(hasDungeonLabelLineOfSight(RAPIER, world, CAMERA, LABEL)).toBe(true);
|
|
} finally { world.free(); }
|
|
});
|
|
|
|
it("does not query past a label or hide one at the camera position", () => {
|
|
const world = new RAPIER.World({ x: 0, y: 0, z: 0 });
|
|
try {
|
|
world.createCollider(RAPIER.ColliderDesc.cuboid(0.1, 3, 3).setTranslation(5, 2, 0));
|
|
world.step();
|
|
expect(hasDungeonLabelLineOfSight(RAPIER, world, CAMERA, LABEL)).toBe(true);
|
|
expect(hasDungeonLabelLineOfSight(RAPIER, world, CAMERA, CAMERA)).toBe(true);
|
|
expect(hasDungeonLabelLineOfSight(RAPIER, world, CAMERA, { x: NaN, y: 2, z: 0 })).toBe(false);
|
|
} finally { world.free(); }
|
|
});
|
|
});
|