Hauptszene scenes/luneraria.tscn, Saumwacht bleibt über --legacy und die alten QA-Schalter erreichbar. Karte aus Bestandsassets plus neuem Turm, HUD mit Planung, Lanes und Minimap, Menü umbenannt, Einstellungen werden aus dem alten Benutzerordner übernommen. Simulation 6,6x schneller (Raster, Caches, faire Staffelung) und exakt spiegelsymmetrisch. Regeln 91/91, echte Anwendung 38/38, Legacy unverändert grün. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
76 lines
2.7 KiB
GDScript
76 lines
2.7 KiB
GDScript
extends Camera3D
|
|
## Overview camera: orthographic three-quarter view over the whole map, pan, zoom and
|
|
## lane focus. Blau's base sits bottom-left, Rot's top-right, as on the minimap.
|
|
|
|
var focus := Vector3.ZERO
|
|
var yaw: float = 0.0
|
|
var pitch: float = deg_to_rad(-56.0)
|
|
var zoom: float = 34.0
|
|
var reduced_motion: bool = false
|
|
var _goal_focus := Vector3.ZERO
|
|
var _goal_zoom: float = 34.0
|
|
var _dragging: bool = false
|
|
|
|
func _ready() -> void:
|
|
projection = PROJECTION_ORTHOGONAL
|
|
near = .1
|
|
far = 400.0
|
|
current = true
|
|
_goal_focus = focus
|
|
_apply()
|
|
|
|
func look_at_point(point: Vector3, new_zoom: float = -1.0, instant: bool = false) -> void:
|
|
_goal_focus = Vector3(clampf(point.x, -40, 40), 0, clampf(point.z, -40, 40))
|
|
if new_zoom > 0.0:
|
|
_goal_zoom = new_zoom
|
|
if instant or reduced_motion:
|
|
focus = _goal_focus
|
|
zoom = _goal_zoom
|
|
_apply()
|
|
|
|
func overview(instant: bool = false) -> void:
|
|
look_at_point(Vector3.ZERO, 46.0, instant)
|
|
|
|
func _apply() -> void:
|
|
size = zoom
|
|
var back := Vector3(0, 0, 1).rotated(Vector3.RIGHT, pitch).rotated(Vector3.UP, yaw)
|
|
position = focus + back * 80.0
|
|
look_at(focus, Vector3.UP)
|
|
|
|
func _process(delta: float) -> void:
|
|
var pan := Vector2(Input.get_axis("ui_left", "ui_right"), Input.get_axis("ui_up", "ui_down"))
|
|
if Input.is_physical_key_pressed(KEY_A): pan.x -= 1
|
|
if Input.is_physical_key_pressed(KEY_D): pan.x += 1
|
|
if Input.is_physical_key_pressed(KEY_W): pan.y -= 1
|
|
if Input.is_physical_key_pressed(KEY_S): pan.y += 1
|
|
if pan != Vector2.ZERO and not _text_focus():
|
|
var right := Vector3(cos(yaw), 0, -sin(yaw))
|
|
var forward := Vector3(-sin(yaw), 0, -cos(yaw))
|
|
_goal_focus += (right * pan.x - forward * pan.y) * zoom * .9 * delta
|
|
var t: float = 1.0 if reduced_motion else minf(1.0, delta * 7.0)
|
|
focus = focus.lerp(_goal_focus, t)
|
|
zoom = lerpf(zoom, _goal_zoom, t)
|
|
_apply()
|
|
|
|
func _text_focus() -> bool:
|
|
var owner: Control = get_viewport().gui_get_focus_owner()
|
|
return owner is LineEdit or owner is TextEdit
|
|
|
|
## World input only; the HUD consumes its own clicks before they reach here.
|
|
func handle_world_input(event: InputEvent) -> bool:
|
|
if event is InputEventMouseButton and event.pressed:
|
|
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
|
|
_goal_zoom = maxf(12.0, _goal_zoom - 2.5)
|
|
return true
|
|
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
|
_goal_zoom = minf(60.0, _goal_zoom + 2.5)
|
|
return true
|
|
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_MIDDLE:
|
|
_dragging = event.pressed
|
|
return true
|
|
if event is InputEventMouseMotion and _dragging:
|
|
var right := Vector3(cos(yaw), 0, -sin(yaw))
|
|
var forward := Vector3(-sin(yaw), 0, -cos(yaw))
|
|
_goal_focus -= (right * event.relative.x - forward * event.relative.y) * zoom / 700.0
|
|
return true
|
|
return false
|