feat(ui): Minimap auf Taste M mit Chunk-Raster, Koordinaten und Klick zum Hinspringen

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Sonnet 5 committed 2026-09-13 11:30:21 +02:00
1 parent c278f62cff
commit 2ece0decb6
4 files changed
+371 -3

No files matched your search

+31 -1
View File
@@ -9,7 +9,9 @@ import { createMaterials } from "./world/materials.js";
import { PropLayer } from "./world/props.js";
import { chunkForWorld, threeToWorld } from "./world/coords.js";
import { createCharacterModule } from "./characters/index.js";
import { playerIsGrounded, playerPosition } from "./player.js";
import { activeVehicleOrNull, playerIsGrounded, playerPosition } from "./player.js";
import { createMap } from "./ui/map.js";
import { headingFromDirection } from "./ui/mapMath.js";
import { createPanel } from "./ui/panel.js";
import { buildAttribution, mountHud } from "./ui/hud.js";
@@ -183,6 +185,34 @@ function requestTeleport(position) {
createPanel({ player, characterModule, scene, manifest, requestTeleport });
// Minimap auf Taste M (docs/superpowers/specs/2026-09-13-minimap-design.md). Position über
// playerPosition — im Fahrzeug liefert die Kapsel nur den lokalen Sitzplatz-Offset. Die Richtung
// kommt aus der Kamera, die zu Fuß der Blickrichtung und im Fahrzeug dessen Richtung folgt.
// Sprünge laufen über requestTeleport und damit über dessen Wartewache bis zum fertigen Chunk.
const MAP_TELEPORT_HEIGHT = 3;
const mapCameraDirection = new Vector3();
const mapVehicleForward = new Vector3();
createMap({
getPosition: () => playerPosition(player),
getHeading: () => {
camera.getWorldDirection(mapCameraDirection);
return headingFromDirection(mapCameraDirection.x, mapCameraDirection.z);
},
getVehicles: () => {
const riding = activeVehicleOrNull(player);
return player.getAllVehicles().map((vehicle) => {
mapVehicleForward.copy(vehicle.forwardLocal).transformDirection(vehicle.vehicleGroup.matrixWorld);
return {
x: vehicle.vehicleGroup.position.x,
z: vehicle.vehicleGroup.position.z,
heading: headingFromDirection(mapVehicleForward.x, mapVehicleForward.z),
occupied: vehicle === riding,
};
});
},
onTeleport: ({ x, z }) => requestTeleport({ x, y: MAP_TELEPORT_HEIGHT, z }),
});
// Meeresboden: man watet hinein, statt endlos zu fallen. Einmalig, nicht je Chunk.
const seafloor = new Mesh(new BoxGeometry(4000, 1, 4000), materials.seafloor);
seafloor.position.set(500, -3.0, -1000); // Oberkante bei y = -2,5