Nicht abgenommen: Nach dem ersten Spieltest wurde entschieden, Champions of Luneraria nach Unity 6 zu portieren. Dieser Stand ist die Referenz für das HUD im Unity-Projekt (../luneraria-unity). - HUD neu aus Komponenten mit eigenem Theme, Porträts aus den echten Modellen (einmal gerendert, zwischengespeichert), Lane-Übersicht mit deterministischer Bedrohung aus öffentlichem Zustand, Bossgrotte, nächste Welle, Ereignisse, Minimap mit zusammengefassten Armeen, Held/Items/Talente, Einheitendetails, Angriffschampions, Bereit-Sperre, UI-Größe, Team-Formen statt nur Farben - Privatsphäre über LuneHudModel: fremdes Gold und fremde Entwürfe erscheinen nie - Keine Regeländerung: Regeln 91/91, M2 73/73, Netz 43/43; verify_g3 715/715; verify_m1 38/38 und verify_m2 14/14 mit angepassten UI-Treibern - Spieltest bis Welle 8 über die echte Oberfläche, Befunde in G3-HUD.md - HELDEN-KONZEPT.md: vom Projektinhaber vorgegebene Helden (nicht umgesetzt) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
72 lines
2.9 KiB
GDScript
72 lines
2.9 KiB
GDScript
class_name LuneEventFeed
|
|
extends VBoxContainer
|
|
## Short event list: tower falls, champions, boss, critical Ancients, round results. At most
|
|
## five entries, newest on top; each fades after a while. A click on an entry with a place
|
|
## moves the camera there. It never lists every kill.
|
|
|
|
signal focus_requested(target: Dictionary)
|
|
|
|
const LIMIT: int = 5
|
|
const LIFETIME: float = 14.0
|
|
const LEVEL_COLORS: Dictionary = {"info": LuneUiTheme.INFO, "good": LuneUiTheme.GOOD, "warn": LuneUiTheme.WARN, "danger": LuneUiTheme.DANGER}
|
|
|
|
var entries: Array[Dictionary] = []
|
|
var _clock: float = 0.0
|
|
|
|
func _init() -> void:
|
|
add_theme_constant_override("separation", 3)
|
|
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
|
|
## level: info, good, warn, danger. target: {} or {"lane": …} / {"point": Vector2} / {"camera": name}.
|
|
func push(text_value: String, level: String = "info", glyph: String = "", target: Dictionary = {}) -> void:
|
|
for entry: Dictionary in entries:
|
|
if entry.text == text_value and _clock - float(entry.born) < 4.0:
|
|
return
|
|
var button := Button.new()
|
|
button.theme_type_variation = "HudRow"
|
|
button.focus_mode = Control.FOCUS_NONE
|
|
button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND if not target.is_empty() else Control.CURSOR_ARROW
|
|
button.custom_minimum_size = Vector2(0, 30)
|
|
var row := HBoxContainer.new()
|
|
row.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
row.offset_left = 8
|
|
row.offset_right = -8
|
|
row.add_theme_constant_override("separation", 7)
|
|
row.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
button.add_child(row)
|
|
var tint: Color = LEVEL_COLORS.get(level, LuneUiTheme.INFO)
|
|
LuneGlyph.make(glyph if not glyph.is_empty() else "star", tint, 15.0, row)
|
|
var label := LuneUiTheme.label(text_value, "HudText", row)
|
|
label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
|
label.clip_text = true
|
|
label.add_theme_color_override("font_color", tint.lerp(LuneUiTheme.TEXT, .45))
|
|
button.pressed.connect(func() -> void:
|
|
if not target.is_empty():
|
|
focus_requested.emit(target))
|
|
LuneTooltip.attach(button, func() -> Dictionary: return {"title": text_value, "note": "Klick: Kamera dorthin" if not target.is_empty() else ""})
|
|
add_child(button)
|
|
move_child(button, 0)
|
|
entries.push_front({"text": text_value, "level": level, "born": _clock, "node": button})
|
|
while entries.size() > LIMIT:
|
|
var old: Dictionary = entries.pop_back()
|
|
(old.node as Node).queue_free()
|
|
visible = true
|
|
|
|
func clear_all() -> void:
|
|
for entry: Dictionary in entries:
|
|
(entry.node as Node).queue_free()
|
|
entries.clear()
|
|
|
|
func _process(delta: float) -> void:
|
|
_clock += delta
|
|
for index: int in range(entries.size() - 1, -1, -1):
|
|
var entry: Dictionary = entries[index]
|
|
var age: float = _clock - float(entry.born)
|
|
var node: Control = entry.node
|
|
if age > LIFETIME:
|
|
node.queue_free()
|
|
entries.remove_at(index)
|
|
elif age > LIFETIME - 2.0:
|
|
node.modulate.a = clampf((LIFETIME - age) / 2.0, 0.0, 1.0)
|
|
visible = not entries.is_empty()
|