scopedvr-map-core/editor/move_math.gd
slyphax 17a8927fec Map-Kern aus dem Editor übernommen (Stand e8ab954)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 15:30:18 +01:00

61 lines
2.8 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends RefCounted
class_name MoveMath
## Shortcuts-Mathe für Karte 2/3 (t_55257792) — bewusst pure Funktionen
## (kein Knoten, keine Kamera): Pfeiltasten-Raster-Schritt + Terrain-
## Pinselgrößen-Zyklus. tests/test_shortcuts.gd prüft headless; main.gd und
## interaction.gd sind nur die dünnen Anwender.
##
## Pfeiltasten-Konvention (Editor-Üblichkeit): „↑" bewegt die Auswahl VON der
## Kamera WEG (in Blickrichtung, horizontal), „↓" auf sie zu, links/rechts
## entsprechend quer. Die Blickrichtung wird auf die NÄCHSTE Weltachse
## gerastet (Godot-Editor-Konvention) — eine Pfeiltaste verschiebt also immer
## exakt entlang X oder Z, nie diagonal.
const NUDGE_STEP_M := 2.0 # eine Rasterzelle pro Tastendruck (Karte 2/3)
## Pfeil-Richtung → Welt-Delta (2 m). yaw_deg = Kamera-Gierwinkel (Orbit ODER
## Flug), fwd = +1 (↑) / −1 (↓), side = +1 (rechts) / −1 (links).
## Die horizontale Blickrichtung (FlyMath.forward_from_euler(yaw, 0)) wird auf
## die nächste Weltachse gerastet: |z| >= |x| → Z-Achse, sonst X-Achse
## (Gleichstand → Z, deterministisch). Rechts = Blickrichtung × oben gekreuzt.
static func nudge_delta(yaw_deg: float, fwd: int, side: int) -> Vector3:
var f := forward_from_euler(yaw_deg, 0.0)
var axis := Vector3.ZERO
if absf(f.z) >= absf(f.x):
axis = Vector3(0.0, 0.0, -1.0) if f.z <= 0.0 else Vector3(0.0, 0.0, 1.0)
else:
axis = Vector3(-1.0, 0.0, 0.0) if f.x <= 0.0 else Vector3(1.0, 0.0, 0.0)
var right := axis.cross(Vector3.UP)
return (axis * float(fwd) + right * float(side)) * NUDGE_STEP_M
## Horizontale Blickrichtung (nur Yaw — identische Formel wie FlyMath, hier
## kopiert statt Abhängigkeit, damit die Datei ohne FlyMath-Load testbar bleibt).
static func forward_from_euler(yaw_deg: float, _pitch_deg: float) -> Vector3:
var yaw := deg_to_rad(yaw_deg)
return Vector3(-sin(yaw), 0.0, -cos(yaw))
# ------------------------------------------------- Terrain-Pinsel-Presets ----
## Pinselgröße-Zyklus durch die 3 Presets (Klein 4 m / Mittel 12 m / Groß 32 m,
## wie die Buttons im Terrain-Panel). up = ] (vergrößern), down = [ (verkleinern).
## Bei einem FREIEN Slider-Wert (nutzergezogen) geht ] zum nächsten Preset
## ÜBER dem Wert, [ zum nächsten DARUNTER — am Rand wird zyklisch gewrappt.
## Rückgabe: der neue Radius in Metern.
static func brush_next_preset(current_m: float, up: bool) -> float:
var presets := [4.0, 12.0, 32.0]
if up:
for r in presets:
if r > current_m + 0.001:
return r
return presets[0] # zyklisch: über dem größten → wieder Klein
# Abwärts: das NÄCHSTE Preset UNTER dem Wert (größtes darunter) —
# rückwärts iterieren, sonst fände die Schleife immer Klein zuerst.
var i := presets.size() - 1
while i >= 0:
if presets[i] < current_m - 0.001:
return presets[i]
i -= 1
return presets[presets.size() - 1] # zyklisch: unter dem kleinsten → Groß