saumwacht-godot/scripts/luneraria/ui/lune_minimap.gd
Martin Stickelbroeck c27a0097c3 M1: spielbarer Drei-Lane-Kern mit Karte, HUD, Menü und Abnahme
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>
2026-09-27 21:37:23 +02:00

66 lines
3.1 KiB
GDScript

extends Control
## Minimap drawn from the authoritative match state. Click or drag to move the camera.
signal focus_requested(point: Vector3)
const TEAM_COLORS: Array[Color] = [Color("5aa8ff"), Color("ff6a55")]
var match_state: LuneMatch
var camera_focus := Vector3.ZERO
var camera_span: float = 34.0
func _ready() -> void:
custom_minimum_size = Vector2(236, 236)
mouse_filter = Control.MOUSE_FILTER_STOP
focus_mode = Control.FOCUS_NONE
tooltip_text = "Minimap · Klicken oder ziehen, um die Kamera zu bewegen"
func to_map(v: Vector2) -> Vector2:
var extent: float = LuneMap.HALF_EXTENT + 4.0
return (v + Vector2(extent, extent)) / (extent * 2.0) * size
func to_world(p: Vector2) -> Vector3:
var extent: float = LuneMap.HALF_EXTENT + 4.0
var v: Vector2 = p / size * extent * 2.0 - Vector2(extent, extent)
return Vector3(v.x, 0, v.y)
func _gui_input(event: InputEvent) -> void:
if (event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT) or (event is InputEventMouseMotion and event.button_mask & MOUSE_BUTTON_MASK_LEFT):
focus_requested.emit(to_world(event.position))
accept_event()
func _draw() -> void:
draw_rect(Rect2(Vector2.ZERO, size), Color(.04, .06, .06, .92))
draw_rect(Rect2(Vector2.ZERO, size), Color("5c4a33"), false, 1.5)
if match_state == null:
return
var a: Vector2 = to_map(Vector2(-40, -40))
var b: Vector2 = to_map(Vector2(40, 40))
draw_line(a, b, Color(.12, .38, .42, .8), 7.0)
for lane: String in LuneMap.LANES:
var path: LuneMap.LanePath = match_state.map.lanes[lane]
var points := PackedVector2Array()
for p: Vector2 in path.points:
points.append(to_map(p))
draw_polyline(points, Color(.62, .56, .42), 4.0, true)
var grotto: Vector2 = to_map(LuneMap.GROTTO)
draw_circle(grotto, 5.0, Color(.55, .35, .75, .85))
var hp: Dictionary = {}
if match_state.phase == LuneMatch.Phase.COMBAT and match_state.combat != null:
for unit: LuneUnit in match_state.combat.units:
if unit.is_mobile() and unit.alive:
draw_circle(to_map(unit.position), 1.8 if unit.kind == "monster" else 2.4, TEAM_COLORS[unit.team].lightened(.2 if unit.kind == "monster" else 0.0))
for definition: Dictionary in match_state.map.buildings:
var alive: bool = match_state.building_alive(definition.id)
if match_state.phase == LuneMatch.Phase.COMBAT and match_state.combat != null and match_state.combat.buildings.has(definition.id):
alive = (match_state.combat.buildings[definition.id] as LuneUnit).alive
var at: Vector2 = to_map(definition.position)
var radius: float = 6.5 if definition.tier == "core" else 4.0
var color: Color = TEAM_COLORS[int(definition.team)]
if alive:
draw_circle(at, radius, color)
draw_arc(at, radius, 0, TAU, 16, Color(1, 1, 1, .6), 1.0)
else:
draw_arc(at, radius, 0, TAU, 16, color.darkened(.3), 1.5)
draw_line(at - Vector2(radius, radius) * .6, at + Vector2(radius, radius) * .6, color.darkened(.3), 1.5)
var center: Vector2 = to_map(Vector2(camera_focus.x, camera_focus.z))
var span: float = camera_span / ((LuneMap.HALF_EXTENT + 4.0) * 2.0) * size.x
draw_rect(Rect2(center - Vector2(span * .9, span * .55), Vector2(span * 1.8, span * 1.1)), Color(1, 1, 1, .55), false, 1.2)