Handkarten als Karten zeichnen statt als Knopfreihe
Auf der Hand standen nur die Namen. Was eine Karte tut, stand allein im Tooltip - man musste jede einzeln anfahren. Jetzt ist jede Karte eine Karte: gezeichnetes Sinnbild, Name, Wirkungstext und ein Dreieck fuer Buff (gruen, hoch) oder Debuff (rot, runter). Die Sinnbilder werden zur Laufzeit gemalt, wie die Wuerfel auch - Bilddateien gibt es im Projekt nicht. Je Karte ein eigenes: Wuerfel, Kreispfeil, Auge, Wolke, Pfeile, durchgestrichener Kreis. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
155
scripts/hud.gd
155
scripts/hud.gd
@@ -56,6 +56,121 @@ var _face := 1
|
|||||||
|
|
||||||
## Ein gezeichnetes Würfelbild: Augen 1-6 oder ein Fragezeichen bei unbekanntem
|
## Ein gezeichnetes Würfelbild: Augen 1-6 oder ein Fragezeichen bei unbekanntem
|
||||||
## Wert. Wird überall dort benutzt, wo früher Ziffern oder Sternchen standen.
|
## Wert. Wird überall dort benutzt, wo früher Ziffern oder Sternchen standen.
|
||||||
|
## Gezeichnetes Sinnbild je Karte. Bilder als Dateien gibt es im Projekt nicht;
|
||||||
|
## alles wird zur Laufzeit gemalt, so wie die Würfel auch.
|
||||||
|
class KartenIcon extends Control:
|
||||||
|
var id := ""
|
||||||
|
var farbe := Color.WHITE
|
||||||
|
|
||||||
|
func _init(karte: String, col: Color, px: float) -> void:
|
||||||
|
id = karte
|
||||||
|
farbe = col
|
||||||
|
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
custom_minimum_size = Vector2(px, px)
|
||||||
|
size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
var s := minf(size.x, size.y)
|
||||||
|
var m := size * 0.5
|
||||||
|
match id:
|
||||||
|
"reroll_all":
|
||||||
|
_wuerfel(m + Vector2(-s * 0.16, -s * 0.06), s * 0.42, 5)
|
||||||
|
_wuerfel(m + Vector2(s * 0.18, s * 0.10), s * 0.42, 2)
|
||||||
|
"reroll_one":
|
||||||
|
_wuerfel(m + Vector2(0, s * 0.10), s * 0.38, 3)
|
||||||
|
_bogen(m + Vector2(0, s * 0.10), s * 0.34)
|
||||||
|
"set_six":
|
||||||
|
_wuerfel(m, s * 0.54, 6)
|
||||||
|
"gain_die":
|
||||||
|
_wuerfel(m + Vector2(-s * 0.10, 0), s * 0.46, 4)
|
||||||
|
_plus(m + Vector2(s * 0.26, -s * 0.20), s * 0.20)
|
||||||
|
"cancel":
|
||||||
|
draw_arc(m, s * 0.30, 0, TAU, 32, farbe, s * 0.08)
|
||||||
|
draw_line(m + Vector2(-s * 0.21, -s * 0.21), m + Vector2(s * 0.21, s * 0.21),
|
||||||
|
farbe, s * 0.08)
|
||||||
|
"peek":
|
||||||
|
_auge(m, s)
|
||||||
|
"bid_up":
|
||||||
|
_pfeil(m, s * 0.52, true)
|
||||||
|
"raise_min":
|
||||||
|
_pfeil(m + Vector2(-s * 0.14, 0), s * 0.44, true)
|
||||||
|
_pfeil(m + Vector2(s * 0.14, 0), s * 0.44, true)
|
||||||
|
"enemy_lower":
|
||||||
|
_pfeil(m, s * 0.52, false)
|
||||||
|
"fog":
|
||||||
|
draw_circle(m + Vector2(-s * 0.16, s * 0.06), s * 0.16, farbe)
|
||||||
|
draw_circle(m + Vector2(s * 0.16, s * 0.06), s * 0.16, farbe)
|
||||||
|
draw_circle(m + Vector2(0, -s * 0.06), s * 0.20, farbe)
|
||||||
|
"gag":
|
||||||
|
var r := Rect2(m - Vector2(s * 0.28, s * 0.16), Vector2(s * 0.56, s * 0.32))
|
||||||
|
draw_rect(r, farbe, false, s * 0.07)
|
||||||
|
draw_line(m + Vector2(-s * 0.28, s * 0.22), m + Vector2(s * 0.28, -s * 0.22),
|
||||||
|
farbe, s * 0.08)
|
||||||
|
_:
|
||||||
|
draw_circle(m, s * 0.26, farbe)
|
||||||
|
|
||||||
|
func _wuerfel(mitte: Vector2, kante: float, augen: int) -> void:
|
||||||
|
var r := Rect2(mitte - Vector2(kante, kante) * 0.5, Vector2(kante, kante))
|
||||||
|
draw_rect(r, farbe, true)
|
||||||
|
var punkt := kante * 0.10
|
||||||
|
var weg := kante * 0.26
|
||||||
|
for p: Vector2 in DieIcon.PIPS[augen]:
|
||||||
|
draw_circle(mitte + p * weg, punkt, Color(0.08, 0.09, 0.12))
|
||||||
|
|
||||||
|
## Offener Kreisbogen mit Spitze - das Zeichen fürs Neuwerfen.
|
||||||
|
func _bogen(mitte: Vector2, r: float) -> void:
|
||||||
|
draw_arc(mitte, r, PI * 0.85, TAU * 0.92, 28, farbe, maxf(1.5, r * 0.20))
|
||||||
|
var spitze := mitte + Vector2(cos(TAU * 0.92), sin(TAU * 0.92)) * r
|
||||||
|
draw_colored_polygon([spitze + Vector2(-r * 0.30, -r * 0.10),
|
||||||
|
spitze + Vector2(r * 0.24, -r * 0.16), spitze + Vector2(r * 0.02, r * 0.28)], farbe)
|
||||||
|
|
||||||
|
func _plus(mitte: Vector2, r: float) -> void:
|
||||||
|
draw_rect(Rect2(mitte - Vector2(r, r * 0.28), Vector2(r * 2, r * 0.56)), farbe, true)
|
||||||
|
draw_rect(Rect2(mitte - Vector2(r * 0.28, r), Vector2(r * 0.56, r * 2)), farbe, true)
|
||||||
|
|
||||||
|
## Der Schaft sitzt hinter der Spitze, sonst überlagern sich beide zu
|
||||||
|
## einem Klecks.
|
||||||
|
func _pfeil(mitte: Vector2, h: float, hoch: bool) -> void:
|
||||||
|
var d := -1.0 if hoch else 1.0
|
||||||
|
var schaft_y: float = mitte.y - d * h * 0.48
|
||||||
|
var oben: float = minf(mitte.y, schaft_y)
|
||||||
|
draw_rect(Rect2(Vector2(mitte.x - h * 0.13, oben),
|
||||||
|
Vector2(h * 0.26, absf(mitte.y - schaft_y))), farbe, true)
|
||||||
|
draw_colored_polygon([mitte + Vector2(0, d * h * 0.50),
|
||||||
|
mitte + Vector2(-h * 0.34, d * h * 0.02),
|
||||||
|
mitte + Vector2(h * 0.34, d * h * 0.02)], farbe)
|
||||||
|
|
||||||
|
func _auge(mitte: Vector2, s: float) -> void:
|
||||||
|
var punkte := PackedVector2Array()
|
||||||
|
for i in 17:
|
||||||
|
var t := -1.0 + 2.0 * i / 16.0
|
||||||
|
punkte.append(mitte + Vector2(t * s * 0.34, -sqrt(maxf(0.0, 1.0 - t * t)) * s * 0.20))
|
||||||
|
for i in 17:
|
||||||
|
var t := 1.0 - 2.0 * i / 16.0
|
||||||
|
punkte.append(mitte + Vector2(t * s * 0.34, sqrt(maxf(0.0, 1.0 - t * t)) * s * 0.20))
|
||||||
|
draw_polyline(punkte, farbe, s * 0.05, true)
|
||||||
|
draw_circle(mitte, s * 0.11, farbe)
|
||||||
|
|
||||||
|
|
||||||
|
## Kleines Zeichen für Buff oder Debuff: Dreieck hoch oder runter.
|
||||||
|
class ArtIcon extends Control:
|
||||||
|
var buff := true
|
||||||
|
|
||||||
|
func _init(ist_buff: bool, px: float) -> void:
|
||||||
|
buff = ist_buff
|
||||||
|
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
custom_minimum_size = Vector2(px, px)
|
||||||
|
size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
var s := minf(size.x, size.y)
|
||||||
|
var m := size * 0.5
|
||||||
|
var col := Color(0.5, 0.9, 0.6) if buff else Color(0.95, 0.5, 0.5)
|
||||||
|
var d := -1.0 if buff else 1.0
|
||||||
|
draw_colored_polygon([m + Vector2(0, d * s * 0.34),
|
||||||
|
m + Vector2(-s * 0.34, -d * s * 0.24), m + Vector2(s * 0.34, -d * s * 0.24)], col)
|
||||||
|
|
||||||
|
|
||||||
class DieIcon extends Control:
|
class DieIcon extends Control:
|
||||||
const PIPS := {
|
const PIPS := {
|
||||||
1: [Vector2(0, 0)],
|
1: [Vector2(0, 0)],
|
||||||
@@ -282,7 +397,7 @@ func _build() -> void:
|
|||||||
|
|
||||||
# --- Handkarten unten links, über der Ansageleiste
|
# --- Handkarten unten links, über der Ansageleiste
|
||||||
hand_panel = _panel()
|
hand_panel = _panel()
|
||||||
_place(hand_panel, 0, 1, 0, 1, 16, -190, 16, -124)
|
_place(hand_panel, 0, 1, 0, 1, 16, -300, 16, -124)
|
||||||
root.add_child(hand_panel)
|
root.add_child(hand_panel)
|
||||||
var hv := VBoxContainer.new()
|
var hv := VBoxContainer.new()
|
||||||
hv.add_theme_constant_override("separation", 4)
|
hv.add_theme_constant_override("separation", 4)
|
||||||
@@ -628,17 +743,45 @@ func _zeichne_hand(st: Dictionary) -> void:
|
|||||||
var b: Dictionary = BoosterDB.get_booster(id)
|
var b: Dictionary = BoosterDB.get_booster(id)
|
||||||
if b.is_empty():
|
if b.is_empty():
|
||||||
continue
|
continue
|
||||||
|
var buff: bool = b.kind == BoosterDB.Kind.BUFF
|
||||||
|
var col := Color(0.5, 0.9, 0.6) if buff else Color(0.95, 0.5, 0.5)
|
||||||
|
|
||||||
var btn := Button.new()
|
var btn := Button.new()
|
||||||
btn.text = String(b.name)
|
btn.custom_minimum_size = Vector2(168, 132)
|
||||||
btn.tooltip_text = String(b.desc)
|
btn.tooltip_text = String(b.desc)
|
||||||
btn.custom_minimum_size = Vector2(0, 40)
|
|
||||||
btn.disabled = not spielbar
|
btn.disabled = not spielbar
|
||||||
var col := Color(0.5, 0.9, 0.6) if b.kind == BoosterDB.Kind.BUFF else Color(0.95, 0.5, 0.5)
|
|
||||||
btn.add_theme_color_override("font_color", col)
|
|
||||||
btn.add_theme_color_override("font_hover_color", Color.WHITE)
|
|
||||||
btn.pressed.connect(_pick.bind(id))
|
btn.pressed.connect(_pick.bind(id))
|
||||||
hand_box.add_child(btn)
|
hand_box.add_child(btn)
|
||||||
|
|
||||||
|
var v := VBoxContainer.new()
|
||||||
|
v.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||||
|
v.offset_left = 9
|
||||||
|
v.offset_top = 7
|
||||||
|
v.offset_right = -9
|
||||||
|
v.offset_bottom = -7
|
||||||
|
v.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
v.add_theme_constant_override("separation", 2)
|
||||||
|
btn.add_child(v)
|
||||||
|
|
||||||
|
var kopf := HBoxContainer.new()
|
||||||
|
kopf.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
v.add_child(kopf)
|
||||||
|
kopf.add_child(KartenIcon.new(id, col, 34.0))
|
||||||
|
var luecke := Control.new()
|
||||||
|
luecke.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
luecke.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
kopf.add_child(luecke)
|
||||||
|
kopf.add_child(ArtIcon.new(buff, 16.0))
|
||||||
|
|
||||||
|
var name_l := _label(String(b.name), 15, col)
|
||||||
|
name_l.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
v.add_child(name_l)
|
||||||
|
var d := _label(String(b.desc), 11, Color(0.78, 0.80, 0.86))
|
||||||
|
d.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||||
|
d.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
d.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||||
|
v.add_child(d)
|
||||||
|
|
||||||
|
|
||||||
func _pick(id: String) -> void:
|
func _pick(id: String) -> void:
|
||||||
if not BoosterDB.needs_target(id) or _my_values.is_empty():
|
if not BoosterDB.needs_target(id) or _my_values.is_empty():
|
||||||
|
|||||||
Reference in New Issue
Block a user