fix(showroom): Funde der Schlussdurchsicht auf der Testseite behoben
Die Spielfigur wirft jetzt einen Schatten (player.init durchlief applyCharacter nie); drei stille Fehlerpfade meckern jetzt statt roh abzubrechen (fehlender Clip fuer die Fingerhaltung, Waffe ohne Griff, mit neuem Test); die Waffenauswahl im Panel zeigt Beschriftungen statt IDs; der Waffen-Umbau prueft jetzt die Meshzahl je Datei; stageTransform ist aus main.js nach lineup.js gezogen und mit dem im Browser gemessenen Fall getestet; slotPosition nimmt DUMMIES als Argument statt es aus dem Modul zu lesen; dazu Kommentar- und Entwurfskorrekturen (Docstring, Beckenspur-Test, Frustum-Culling, Port/Kamera/ VIEW_DISTANCE im Entwurf). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c8f1832eae
commit
a0cd95cceb
9 files changed
+97
-18
No files matched your search
@@ -58,9 +58,17 @@ describe("createDummy", () => {
|
||||
right.name = "hand_r";
|
||||
const left = new Bone();
|
||||
left.name = "hand_l";
|
||||
// Ziele der Fingerspuren aus `fingers` unten (index_01_r, thumb_03_l) — ohne sie meldet three.js beim
|
||||
// Binden für jeden Testlauf "No target node found for track".
|
||||
const indexR = new Bone();
|
||||
indexR.name = "index_01_r";
|
||||
const thumbL = new Bone();
|
||||
thumbL.name = "thumb_03_l";
|
||||
root.add(pelvis);
|
||||
pelvis.add(right);
|
||||
pelvis.add(left);
|
||||
right.add(indexR);
|
||||
left.add(thumbL);
|
||||
return root;
|
||||
}
|
||||
const clip = new AnimationClip("take", 1, [
|
||||
@@ -94,8 +102,20 @@ describe("createDummy", () => {
|
||||
const root = new Group();
|
||||
const pelvis = new Bone();
|
||||
pelvis.name = "pelvis";
|
||||
const indexR = new Bone();
|
||||
indexR.name = "index_01_r";
|
||||
const thumbL = new Bone();
|
||||
thumbL.name = "thumb_03_l";
|
||||
root.add(pelvis);
|
||||
pelvis.add(indexR);
|
||||
pelvis.add(thumbL);
|
||||
expect(() => createDummy({ template: root, clip, fingers, weapon, hand: "r", grip: WEAPON_GRIP }))
|
||||
.toThrow(/Dummy ohne Knochen hand_r/);
|
||||
});
|
||||
|
||||
// Bruch: Waffe ohne Griff — applyGrip bekäme kein Objekt und bräche mit einem rohen TypeError ab.
|
||||
it("meldet eine Waffe ohne Griff", () => {
|
||||
expect(() => createDummy({ template: template(), clip, fingers, weapon, hand: "r", grip: null }))
|
||||
.toThrow(/Waffe ohne Griff/);
|
||||
});
|
||||
});
|
||||
+23
-2
@@ -6,7 +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";
|
||||
import { DUMMIES, labelLines, slotPosition, stageTransform, 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));
|
||||
@@ -102,7 +102,9 @@ describe("weapons-mocap.glb", () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Bruch: Drift nicht abgezogen — der Dummy wanderte von seinem Platz.
|
||||
// Bruch: Drift nicht abgezogen — der Dummy wanderte von seinem Platz. Geprüft werden die lokalen
|
||||
// Komponenten x und y, weil die Beckenspur im Raum von root liegt (−90° um X) und die Höhe dort auf der
|
||||
// lokalen z-Achse sitzt, nicht auf y.
|
||||
it("beginnt jede Beckenbahn waagrecht bei 0", () => {
|
||||
for (const animation of animations) {
|
||||
const translation = animation.listChannels().find((channel) => channel.getTargetPath() === "translation");
|
||||
@@ -187,4 +189,23 @@ describe("Aufstellung", () => {
|
||||
expect(labelLines(DUMMIES[0])).toEqual(["Pistole nachladen · Take 1", "Pistole"]);
|
||||
expect(labelLines(DUMMIES.at(-1))).toEqual(["Bogenschütze · Take 1", "ohne Waffe"]);
|
||||
});
|
||||
|
||||
// Bruch: falsches Vorzeichen bei Position oder Drehwinkel — die Aufstellung stünde seitlich versetzt, oder
|
||||
// die Dummies schauten an der Figur vorbei statt sie anzusehen.
|
||||
it("stellt die Aufstellung bei Blick nach +Z 8 × Maßstab vor die Figur und dreht sie um 180°", () => {
|
||||
const { x, z, rotationY } = stageTransform({ x: 0, z: 0 }, { x: 0, z: 1 }, 1);
|
||||
expect(x).toBeCloseTo(0, 10);
|
||||
expect(z).toBeCloseTo(8, 10);
|
||||
// Math.atan2(-0, -1) liefert −π statt π (Vorzeichen der Null) — dieselbe Halbdrehung, deshalb Betrag.
|
||||
expect(Math.abs(rotationY)).toBeCloseTo(Math.PI, 10);
|
||||
});
|
||||
|
||||
// Im Browser gemessener Fall (task-8-browsercheck.md): Figur bei (0|0), Maßstab 0,4921, Ergebnis
|
||||
// (−3,94|0) und 90°.
|
||||
it("stellt die Aufstellung bei Blick nach −X 8 × Maßstab vor die Figur und dreht sie um 90°", () => {
|
||||
const { x, z, rotationY } = stageTransform({ x: 0, z: 0 }, { x: -1, z: 0 }, 0.4921);
|
||||
expect(x).toBeCloseTo(-3.94, 2);
|
||||
expect(z).toBeCloseTo(0, 10);
|
||||
expect(rotationY).toBeCloseTo(Math.PI / 2, 10);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user