feat(world): Parkwege, Felder, Plätze, Pool und Parkplatz als eigene Schichten
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e675e62a16
commit
b736afb7ff
10 files changed
+96
-17
No files matched your search
@@ -101,6 +101,27 @@ describe("geometry", () => {
|
||||
expect(out.urban).toBeNull();
|
||||
});
|
||||
|
||||
it("baut Parkwege flach auf Straßenhöhe und die neuen Flächenarten wie Beläge", () => {
|
||||
const chunk = {
|
||||
chunk: [0, 0], origin: [0, 0], land: [], roads: [], centerlines: [], palms: [], buildings: [],
|
||||
surfaces: ["field", "court", "pool", "parking"].map((kind) => ({ poly: PLOT, kind })),
|
||||
paths: [{ poly: COURTYARD }],
|
||||
};
|
||||
const out = buildChunkGeometry(chunk);
|
||||
for (const kind of ["field", "court", "pool", "parking"]) {
|
||||
const box = new Box3().setFromBufferAttribute(out[kind].getAttribute("position"));
|
||||
expect(box.max.y, kind).toBeCloseTo(0.02);
|
||||
}
|
||||
const paths = new Box3().setFromBufferAttribute(out.paths.getAttribute("position"));
|
||||
expect(paths.min.y).toBeCloseTo(0.03);
|
||||
expect(footprintArea(out.paths)).toBeCloseTo(800, 6); // Weg um einen Hof: das Loch bleibt offen
|
||||
});
|
||||
|
||||
it("liefert ohne Parkwege null statt einer leeren Geometrie", () => {
|
||||
const chunk = { chunk: [0, 0], origin: [0, 0], land: [PLOT], surfaces: [], roads: [], centerlines: [], buildings: [], palms: [] };
|
||||
expect(buildChunkGeometry(chunk).paths).toBeNull();
|
||||
});
|
||||
|
||||
it("gibt Gebäuden eine Farbe je Haus", () => {
|
||||
const chunk = { chunk: [0, 0], origin: [0, 0], land: [], surfaces: [], roads: [], centerlines: [], palms: [],
|
||||
buildings: [{ poly: PLOT, height: 9, source: "district", speculative: false }] };
|
||||
|
||||
+14
-6
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { applyPolygonOffsets, MATERIAL_KEYS, POLYGON_OFFSETS, POLYGON_OFFSET_ORDER, TEXTURES,
|
||||
import { applyPolygonOffsets, MATERIAL_KEYS, POLYGON_OFFSETS, POLYGON_OFFSET_ORDER, SURFACE_COLORS, TEXTURES,
|
||||
waterNormalData } from "../src/world/materials.js";
|
||||
import { buildChunkGeometry } from "../src/world/geometry.js";
|
||||
|
||||
@@ -9,8 +9,15 @@ describe("materials", () => {
|
||||
expect(Object.keys(buildChunkGeometry(chunk)).sort()).toEqual([...MATERIAL_KEYS].sort());
|
||||
});
|
||||
|
||||
it("nennt für jedes Material eine Textur", () => {
|
||||
for (const key of MATERIAL_KEYS) expect(TEXTURES[key]).toBeTruthy();
|
||||
it("nennt für jedes Material genau eine Textur oder eine Farbe", () => {
|
||||
for (const key of MATERIAL_KEYS) expect(Boolean(TEXTURES[key]) !== Boolean(SURFACE_COLORS[key]), key).toBe(true);
|
||||
});
|
||||
|
||||
it("gibt Feldern das Gras des Parks, dem Parkplatz den Asphalt der Straßen und Wegen Betonplatten", () => {
|
||||
expect(TEXTURES.field).toBe(TEXTURES.park);
|
||||
expect(TEXTURES.parking).toBe(TEXTURES.roads);
|
||||
expect(TEXTURES.paths).toBe("concrete_pavement");
|
||||
expect(Object.keys(SURFACE_COLORS).sort()).toEqual(["court", "pool"]);
|
||||
});
|
||||
|
||||
it("deckt Strand und Park mit eigenen Materialien ab", () => {
|
||||
@@ -40,8 +47,8 @@ describe("materials", () => {
|
||||
// Datenstruktur, applyPolygonOffsets() eine reine Funktion auf Platzhalterobjekten — beide
|
||||
// brauchen weder createMaterials() noch echtes Texturladen.
|
||||
describe("Tiefenpuffer-Versatz je Schicht (gegen Flackern zwischen Boden/Stadt/Park/Strand/Straße)", () => {
|
||||
it("ordnet die Schichten Boden < Stadtfläche < Park < Strand < Straße", () => {
|
||||
expect(POLYGON_OFFSET_ORDER).toEqual(["ground", "urban", "park", "sand", "roads"]);
|
||||
it("ordnet die Schichten Boden < Stadtfläche < Park < Strand < Feld < Platz < Pool < Parkplatz < Weg < Straße", () => {
|
||||
expect(POLYGON_OFFSET_ORDER).toEqual(["ground", "urban", "park", "sand", "field", "court", "pool", "parking", "paths", "roads"]);
|
||||
});
|
||||
|
||||
it("aktiviert polygonOffset für jede der fünf Schichten", () => {
|
||||
@@ -72,7 +79,8 @@ describe("Tiefenpuffer-Versatz je Schicht (gegen Flackern zwischen Boden/Stadt/P
|
||||
it("trägt den Versatz nur in Boden/Stadtfläche/Park/Strand/Straße ein — Brücken, Gebäude, "
|
||||
+ "Wasser und Meeresboden bleiben unberührt (eigene Materialobjekte, s. Auftrag)", () => {
|
||||
const fake = Object.fromEntries(
|
||||
["ground", "urban", "park", "sand", "roads", "bridges", "buildings", "water", "seafloor"]
|
||||
["ground", "urban", "park", "sand", "field", "court", "pool", "parking", "paths", "roads",
|
||||
"bridges", "buildings", "water", "seafloor"]
|
||||
.map((k) => [k, {}]),
|
||||
);
|
||||
applyPolygonOffsets(fake);
|
||||
|
||||
@@ -221,6 +221,24 @@ describe("ChunkStreamer", () => {
|
||||
expect(source.children).toHaveLength(1);
|
||||
expect(source.children[0].geometry.getAttribute("color")).toBeUndefined(); // die Landplatte, kein Gebäude
|
||||
});
|
||||
|
||||
// Bruch: eine neue Schicht fehlt in DECALS — Weg oder Feld landete in der Kollision und die Kapsel stolperte
|
||||
// über 2–3 cm hohe Kanten, oder die Schicht fehlte ganz in der Szene.
|
||||
it("legt Parkwege und die neuen Flächenarten als Auflagen ohne Kollision in die Szene", async () => {
|
||||
const square = [[[0, 0], [20, 0], [20, 20], [0, 20]]];
|
||||
const chunk = {
|
||||
chunk: [4, 6], origin: [0, -1000], land: [square], roads: [], buildings: [],
|
||||
surfaces: ["field", "court", "pool", "parking"].map((kind) => ({ poly: square, kind })),
|
||||
paths: [{ poly: square }],
|
||||
};
|
||||
const { streamer, player, scene } = makeStreamer(chunk);
|
||||
streamer.update(emptyChunkCenter);
|
||||
await flush();
|
||||
|
||||
expect(player.addCollider.mock.calls[0][0].shape.source.children).toHaveLength(1); // nur die Landplatte
|
||||
const group = scene.add.mock.calls[0][0];
|
||||
expect(group.children.filter((child) => child.isMesh)).toHaveLength(5);
|
||||
});
|
||||
});
|
||||
|
||||
// Fix-Runde 2, Befund C / Ruling 64: der Zweig `if (this.props)` in #load hatte keine
|
||||
|
||||
Reference in new issue
Block a user