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>
66 lines
3.1 KiB
GDScript
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)
|