class_name HudOverlay extends Control ## Zeichnet Lebens- und Manabalken, Rolle, Sterne und Schadenszahlen ## über die 3D-Einheiten. Spielt außerdem die Kampfgeräusche ab. const FLOAT_TIME := 0.9 const FLOAT_RISE := 42.0 var board: BoardView3D = null var sfx: Sfx = null var _font: Font var _floaters: Array = [] ## {"world": Vector3, "text": String, "col": Color, "age": float} var _combat_seen: Combat = null func _ready() -> void: _font = ThemeDB.fallback_font mouse_filter = Control.MOUSE_FILTER_IGNORE set_process(true) func _process(delta: float) -> void: _pull_hits() for f in _floaters: f["age"] += delta _floaters = _floaters.filter(func(f): return f["age"] < FLOAT_TIME) queue_redraw() ## Holt neue Treffer aus dem laufenden Spielerkampf und macht Zahlen und Töne daraus. func _pull_hits() -> void: if board == null or board.game == null: return var c: Combat = board.game.player_combat if c == null or not c.record_hits: _combat_seen = null return if c != _combat_seen: _combat_seen = c _floaters.clear() if c.hits.is_empty(): return var my_team := board.game.human_team_in_combat() for h in c.hits: var world := board.world_pos(board.mirror_for_view(h["pos"], my_team)) var mine: bool = h["team"] == my_team match h["kind"]: "dmg": _floaters.append({"world": world, "text": str(h["amount"]), "col": Color(1.0, 0.55, 0.45) if mine else Color(1.0, 0.95, 0.85), "age": 0.0}) if sfx: sfx.play("treffer") "crit": _floaters.append({"world": world, "text": str(h["amount"]) + "!", "col": Color(1.0, 0.85, 0.3), "age": 0.0}) if sfx: sfx.play("krit") "heal": _floaters.append({"world": world, "text": "+" + str(h["amount"]), "col": Color(0.55, 1.0, 0.6), "age": 0.0}) if sfx: sfx.play("heilung") "cast": if sfx: sfx.play("zauber") "attack": var from := board.world_pos(board.mirror_for_view(h["from"], my_team)) board.spawn_attack(from, world, h["ranged"], Data.ELEMENT_COLORS[h["element"]]) c.hits.clear() func _draw() -> void: if board == null or board.camera == null: return var cam := board.camera for d in board.draw_units: var world: Vector3 = d["pos"] if cam.is_position_behind(world): continue var head := cam.unproject_position(world + Vector3(0.0, 1.35, 0.0)) var foot := cam.unproject_position(world + Vector3(0.0, 0.05, 0.0)) var a: Avatar = d["avatar"] var side: int = d["side"] var bw: float = clampf(absf(foot.y - head.y) * 0.85, 26.0, 70.0) var bx := head.x - bw * 0.5 var by := head.y - 4.0 draw_rect(Rect2(bx - 1.0, by - 1.0, bw + 2.0, 8.0), Color(0.05, 0.05, 0.07, 0.85)) draw_rect(Rect2(bx, by, bw * clampf(d["hp"], 0.0, 1.0), 6.0), Color(0.35, 0.85, 0.42) if side == 0 else Color(0.92, 0.38, 0.38)) if d["mana"] > 0.0: draw_rect(Rect2(bx, by + 7.0, bw, 4.0), Color(0.05, 0.05, 0.07, 0.85)) draw_rect(Rect2(bx, by + 7.0, bw * clampf(d["mana"], 0.0, 1.0), 4.0), Color(0.35, 0.62, 0.95)) # Schild als heller Streifen über dem Lebensbalken. if d.get("shield", 0.0) > 0.0: draw_rect(Rect2(bx, by - 4.0, bw * clampf(d["shield"], 0.0, 1.0), 3.0), Color(0.85, 0.9, 1.0)) for s in a.star: draw_circle(Vector2(bx + bw * 0.5 - 7.0 + 7.0 * float(s), by - 9.0), 2.6, Color(1.0, 0.85, 0.25)) draw_string(_font, Vector2(bx + bw + 4.0, by + 7.0), Data.ROLE_SHORT[a.role], HORIZONTAL_ALIGNMENT_LEFT, -1, 13, Color(0.9, 0.9, 0.95, 0.9)) if d["cast"]: draw_arc(foot, bw * 0.55, 0.0, TAU, 24, Color(1.0, 0.95, 0.5, 0.9), 2.5) # Zustände als kleine Marken neben dem Balken. var marks := [] if d.get("burn", false): marks.append(["B", Color(1.0, 0.5, 0.2)]) if d.get("slow", false): marks.append(["S", Color(0.6, 0.85, 1.0)]) if d.get("stun", false): marks.append(["Z", Color(1.0, 0.9, 0.3)]) for i in marks.size(): draw_string(_font, Vector2(bx - 12.0 - 11.0 * float(i), by + 7.0), marks[i][0], HORIZONTAL_ALIGNMENT_LEFT, -1, 12, marks[i][1]) # Schwebende Zahlen for f in _floaters: var t: float = f["age"] / FLOAT_TIME var pos := cam.unproject_position(f["world"] + Vector3(0.0, 1.5, 0.0)) pos.y -= t * FLOAT_RISE var col: Color = f["col"] col.a = 1.0 - t * t var size := 15 if f["text"].ends_with("!") else 13 draw_string(_font, pos + Vector2(1, 1), f["text"], HORIZONTAL_ALIGNMENT_CENTER, -1, size, Color(0, 0, 0, col.a * 0.8)) draw_string(_font, pos, f["text"], HORIZONTAL_ALIGNMENT_CENTER, -1, size, col)