feat: live settings panel (≈45 Werte, Live/Reload, Persistenz, AO live)

- panel.js: Drawer-Panel (P / ⚙), schema-getrieben, ●live/⟳reload-Badges
- Werte direkt im Panel einstellbar statt in config.js grabben
- Live-Apply über mutateNested (nur Plain-Objekte, nie Modul-Namespace)
  + registerApply-Callbacks für Three.js-Objekte (FOV, Belichtung, Fog, Licht, Schatten-Frustum, Bloom)
- PLAYER.*/CONTROLS.* live (player.js liest jeden Frame neu)
- AO jetzt live: debounced world.markAllDirty() remesht alle Chunks ohne F5
- Reload-Pflichtige Werte persistiert + blinkender Neu-Starten-Button
  (Seed, Meereshöhe, Spawn, MSAA, Tone-Mapping, Schatten an/Größe, AO-Level)
- Persistenz: localStorage (debounced), config.js lädt beim Start
- HUD/Overlay ausgeblendet, solange das Panel offen ist (Welt frei sichtbar)
- Buttons: Neu starten, Auf Standard zurücksetzen, Werte kopieren (JSON)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
minecraft-cloneandClaude committed 2026-06-21 16:31:25 +02:00
1 parent d6f6774815
commit 6e8e207afa
7 files changed
+775 -78

No files matched your search

+16 -13
View File
@@ -1,10 +1,12 @@
// First-Person-Spieler: Bewegung, Gravitation, AABB-Kollision, Springen,
// Flug-Modus, Schwimmen. yaw/pitch steuern die Kamera (extern gesetzt).
//
// WICHTIG: PLAYER- und CONTROLS-Werte werden LIVE aus config.js gelesen
// (jeder Frame), nicht beim Laden destrukturiert. So kann das Settings-
// Panel Geschwindigkeit/Gravitation/Maus-Empfindlichkeit usw. zur
// Laufzeit ändern.
import { isSolid, BLOCK } from './constants.js';
import { PLAYER, MOUSE_SENSITIVITY } from './config.js';
// Werte aus config.js (PLAYER). Lokal gebunden, damit die Verwendungen kurz bleiben.
const { HALF, HEIGHT, EYE, GRAVITY, JUMP_VEL, WALK, SPRINT, FLY_SPEED, MAX_FALL } = PLAYER;
import { PLAYER, CONTROLS } from './config.js';
export class Player {
constructor(world) {
@@ -23,21 +25,21 @@ export class Player {
}
eyePosition(out) {
out.set(this.pos[0], this.pos[1] + EYE, this.pos[2]);
out.set(this.pos[0], this.pos[1] + PLAYER.EYE, this.pos[2]);
return out;
}
inWater() {
// Pruefe den Block auf Augen- und Fuss-Hoehe
const ex = Math.floor(this.pos[0]);
const ey = Math.floor(this.pos[1] + EYE * 0.6);
const ey = Math.floor(this.pos[1] + PLAYER.EYE * 0.6);
const ez = Math.floor(this.pos[2]);
return this.world.getBlock(ex, ey, ez) === BLOCK.WATER;
}
update(input, dt) {
// --- Maus-Look ---
const sens = MOUSE_SENSITIVITY;
// --- Maus-Look (Empfindlichkeit live aus config) ---
const sens = CONTROLS.MOUSE_SENSITIVITY;
this.yaw -= input.mouseDX * sens;
this.pitch -= input.mouseDY * sens;
const lim = Math.PI / 2 - 0.001;
@@ -69,7 +71,7 @@ export class Player {
// ShiftLeft/Right dient im Fly-Modus gleichzeitig als "Runter" – kein
// Konflikt, da Sprint nur beim Gehen greift (Fly nutzt konstante FLY_SPEED).
const sprint = input.down('ShiftLeft') || input.down('ShiftRight');
const speed = this.flying ? FLY_SPEED : (sprint ? SPRINT : WALK);
const speed = this.flying ? PLAYER.FLY_SPEED : (sprint ? PLAYER.SPRINT : PLAYER.WALK);
if (this.flying) {
this.vel[0] = mx * speed;
@@ -85,14 +87,14 @@ export class Player {
this.vel[2] = mz * move;
// Gravitation / Schwimmen
if (water) {
this.vel[1] -= GRAVITY * 0.28 * dt;
this.vel[1] -= PLAYER.GRAVITY * 0.28 * dt;
if (this.vel[1] < -6) this.vel[1] = -6;
if (input.down('Space')) this.vel[1] = 4.0; // nach oben schwimmen
} else {
this.vel[1] -= GRAVITY * dt;
if (this.vel[1] < -MAX_FALL) this.vel[1] = -MAX_FALL;
this.vel[1] -= PLAYER.GRAVITY * dt;
if (this.vel[1] < -PLAYER.MAX_FALL) this.vel[1] = -PLAYER.MAX_FALL;
if (input.down('Space') && this.onGround) {
this.vel[1] = JUMP_VEL;
this.vel[1] = PLAYER.JUMP_VEL;
this.onGround = false;
}
}
@@ -110,6 +112,7 @@ export class Player {
this.pos[axis] += amount;
if (amount === 0) return;
const HALF = PLAYER.HALF, HEIGHT = PLAYER.HEIGHT;
const x = this.pos[0], y = this.pos[1], z = this.pos[2];
const minX = Math.floor(x - HALF), maxX = Math.floor(x + HALF);
const minY = Math.floor(y), maxY = Math.floor(y + HEIGHT - 0.001);