feat(showroom): Aufstellung der 13 Dummies mit Clips und Waffen
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4422432998
commit
149ec9c5d9
2 files changed
+123
No files matched your search
@@ -6,6 +6,7 @@ import { ALL_EXTENSIONS } from "@gltf-transform/extensions";
|
||||
import { getBounds } from "@gltf-transform/functions";
|
||||
import { MeshoptDecoder } from "meshoptimizer";
|
||||
import { TEXTURE_SIZE, WEAPON_SOURCES } from "../tools/assets/weapons.mjs";
|
||||
import { DUMMIES, labelLines, slotPosition, WEAPONS } from "../src/showroom/lineup.js";
|
||||
|
||||
describe.each(WEAPON_SOURCES.map((source) => [source.id, source]))("%s.glb", (id, source) => {
|
||||
const file = fileURLToPath(new URL(`../public/models/weapons/${id}.glb`, import.meta.url));
|
||||
@@ -121,3 +122,69 @@ describe("weapons-mocap.glb", () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("Aufstellung", () => {
|
||||
it("stellt 13 Dummies auf, acht mit Waffe", () => {
|
||||
expect(DUMMIES).toHaveLength(13);
|
||||
expect(DUMMIES.filter((dummy) => dummy.weapon)).toHaveLength(8);
|
||||
});
|
||||
|
||||
// Bruch: Tippfehler im Clipnamen — der Dummy bliebe regungslos stehen.
|
||||
it("nennt nur Clips, die es in weapons-mocap.glb gibt", () => {
|
||||
for (const dummy of DUMMIES) expect(CLIP_IDS).toContain(dummy.clip);
|
||||
});
|
||||
|
||||
it("spielt jeden Clip mindestens einmal", () => {
|
||||
expect(new Set(DUMMIES.map((dummy) => dummy.clip)).size).toBe(CLIP_IDS.length);
|
||||
});
|
||||
|
||||
// Bruch: Waffe ohne Datei oder ohne Griff — leere Hand oder Waffe im Boden.
|
||||
it("gibt jeder Waffe Datei, Beschriftung und Griff", () => {
|
||||
expect(Object.keys(WEAPONS)).toEqual(WEAPON_SOURCES.map((source) => source.id));
|
||||
for (const [id, weapon] of Object.entries(WEAPONS)) {
|
||||
expect(weapon.url).toBe(`./models/weapons/${id}.glb`);
|
||||
expect(statSync(fileURLToPath(new URL(`../public/models/weapons/${id}.glb`, import.meta.url))).size)
|
||||
.toBeGreaterThan(0);
|
||||
expect(weapon.grip.position).toHaveLength(3);
|
||||
expect(weapon.grip.rotation).toHaveLength(3);
|
||||
expect(weapon.label.length).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
it("hält jede Waffe in einer Hand und lässt sonst beide leer", () => {
|
||||
for (const dummy of DUMMIES) {
|
||||
if (dummy.weapon) {
|
||||
expect(WEAPONS[dummy.weapon]).toBeDefined();
|
||||
expect(["r", "l"]).toContain(dummy.hand);
|
||||
} else {
|
||||
expect(dummy.hand).toBeNull();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Bruch: zwei Dummies auf einem Platz oder ineinander — die Schleifen wären nicht mehr auseinanderzuhalten.
|
||||
it("hält 3,5 m Abstand zwischen allen Plätzen", () => {
|
||||
const spots = DUMMIES.map((_, index) => slotPosition(index));
|
||||
for (let i = 0; i < spots.length; i++) {
|
||||
for (let k = i + 1; k < spots.length; k++) {
|
||||
expect(Math.hypot(spots[i].x - spots[k].x, spots[i].z - spots[k].z)).toBeGreaterThanOrEqual(3.5);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Bruch: der Bogenschütze wandert 3,13 m und liefe sonst durch seine Nachbarn.
|
||||
it("lässt dem Bogenschützen mindestens 4 m Platz", () => {
|
||||
const index = DUMMIES.findIndex((dummy) => dummy.clip === "hunter_bowArrow_tk01");
|
||||
const bow = slotPosition(index);
|
||||
for (let i = 0; i < DUMMIES.length; i++) {
|
||||
if (i === index) continue;
|
||||
const other = slotPosition(i);
|
||||
expect(Math.hypot(bow.x - other.x, bow.z - other.z)).toBeGreaterThanOrEqual(4);
|
||||
}
|
||||
});
|
||||
|
||||
it("beschriftet mit Clip und Waffe", () => {
|
||||
expect(labelLines(DUMMIES[0])).toEqual(["Pistole nachladen · Take 1", "Pistole"]);
|
||||
expect(labelLines(DUMMIES.at(-1))).toEqual(["Bogenschütze · Take 1", "ohne Waffe"]);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user