update
This commit is contained in:
@@ -1,25 +1,37 @@
|
||||
class_name CardView
|
||||
extends Control
|
||||
## Zeichnet eine Karte (Hand, Sammlung, Booster, Vorschau).
|
||||
## Zeichnet eine Karte (Laden, Hand, Sammlung, Booster, Vorschau).
|
||||
## Aufbau wie bei Hearthstone: Kostenkristall oben links, Bild, Namensband, Schlüsselwörter als
|
||||
## Symbole, Effekttext, Angriff und Leben als Kreise unten. Das Element steht im Hintergrund,
|
||||
## die Seltenheit in Rahmen, Glanz und Edelstein. Sehr flache Karten (Hand) zeigen nur das Nötigste.
|
||||
|
||||
signal clicked(view: CardView)
|
||||
signal hover(card: Cards.Card, entered: bool)
|
||||
|
||||
var card: Cards.Card
|
||||
var border = null # Color oder null (dann Seltenheitsfarbe)
|
||||
var rarity := "gewöhnlich" # nur Optik: Rahmenfarbe der eigenen Stufe
|
||||
var border = null # Color oder null (dann Rahmen der Seltenheitsstufe)
|
||||
var rarity := "gewöhnlich" # nur Optik
|
||||
var dim := false
|
||||
var bonus := 0 # Vorschau im Kampf: Angriff, den die Karte auf dem Feld dazubekäme
|
||||
var tag := "" # Vorschau im Kampf: Feldkombo, die das Ausspielen auslöst
|
||||
var lift := false # hebt sich beim Zeigen an (Hand und Laden)
|
||||
|
||||
|
||||
## focusable: per Gamepad oder Tab anwählbar (Sammlung, Booster); A bzw. Enter wirkt wie ein Klick.
|
||||
func _init(c: Cards.Card, sz: Vector2, focusable: bool = false, rar: String = "gewöhnlich") -> void:
|
||||
card = c
|
||||
rarity = rar
|
||||
set_process(Style.rarity_animated(rarity)) # bewegter Glanz
|
||||
custom_minimum_size = sz
|
||||
size = sz
|
||||
pivot_offset = sz / 2
|
||||
mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
mouse_entered.connect(func(): hover.emit(card, true))
|
||||
mouse_exited.connect(func(): hover.emit(card, false))
|
||||
mouse_entered.connect(func():
|
||||
hover.emit(card, true)
|
||||
_lift(true))
|
||||
mouse_exited.connect(func():
|
||||
hover.emit(card, false)
|
||||
_lift(false))
|
||||
if focusable:
|
||||
focus_mode = Control.FOCUS_ALL
|
||||
focus_entered.connect(func():
|
||||
@@ -30,6 +42,17 @@ func _init(c: Cards.Card, sz: Vector2, focusable: bool = false, rar: String = "g
|
||||
queue_redraw())
|
||||
|
||||
|
||||
func _lift(up: bool) -> void:
|
||||
if not lift or not Style.animations:
|
||||
return
|
||||
z_index = 1 if up else 0
|
||||
create_tween().tween_property(self, "scale", Vector2(1.07, 1.07) if up else Vector2.ONE, 0.1).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
|
||||
accept_event()
|
||||
@@ -41,47 +64,135 @@ func _gui_input(event: InputEvent) -> void:
|
||||
|
||||
func _draw() -> void:
|
||||
var rect := Rect2(Vector2.ZERO, size)
|
||||
var big := size.x >= 180
|
||||
var mid := size.x >= 115
|
||||
var f_name := 18 if big else (14 if mid else 12)
|
||||
var f_text := 14 if big else (11 if mid else 10)
|
||||
var f_stat := 24 if big else (18 if mid else 15)
|
||||
var seed := hash(card.id)
|
||||
var frame: Color = border if border != null else Style.rarity_frame(rarity, seed)
|
||||
if rarity != "gewöhnlich":
|
||||
Style.glow(self, rect, Style.rarity_color(rarity, seed), 8, 8 if size.x >= 180 else 6)
|
||||
Style.fill_elements(self, rect, card.elements, 8)
|
||||
var bcol: Color = border if border != null else Cards.RARITY_COLORS[rarity]
|
||||
Style.border(self, rect, bcol, 3 if big else 2, 8)
|
||||
# Kosten
|
||||
var r := 16 if big else 12
|
||||
var cc := Vector2(r + 4, r + 4)
|
||||
draw_circle(cc, r, Color("14141c"))
|
||||
Style.text(self, str(card.cost), f_stat, Style.GOLD, cc, "center", true)
|
||||
# Name und Kombo
|
||||
var name_left := 2 * r + 10
|
||||
var nm := Style.fit(card.title(), true, f_name, size.x - name_left - 6)
|
||||
Style.text(self, nm, f_name, Style.TEXT, Vector2((name_left + size.x - 6) / 2.0, 4), "midtop", true)
|
||||
if mid:
|
||||
var sub: String = tr(card.combo()) if card.is_combo() else ""
|
||||
Style.text(self, sub, f_text, Color("e6e6e6"), Vector2(size.x / 2, 2 * r + 4), "midtop")
|
||||
# Textfeld: Höhe folgt dem umbrochenen Text und der Schriftgröße, das Bild bekommt den Rest
|
||||
var tsize := Style.fs(f_text)
|
||||
var text_w: float = size.x - 20
|
||||
var needed: float = Style.FONT.get_multiline_string_size(card.text(), HORIZONTAL_ALIGNMENT_LEFT, text_w, tsize).y + 8 if card.text() != "" else size.y * 0.42
|
||||
var box_bottom: float = size.y - (28 if big else 22)
|
||||
var band_top: float = 2 * r + 4 + (f_text + 6 if mid else 0) # unter Name und Kombo
|
||||
var box_top: float = maxf(maxf(size.y * 0.30, band_top), box_bottom - maxf(needed, size.y * 0.42))
|
||||
var box := Rect2(6, box_top, size.x - 12, box_bottom - box_top)
|
||||
# Bild
|
||||
var band_bottom: float = box_top - 4
|
||||
if band_bottom - band_top > 14:
|
||||
var gsize: float = minf(band_bottom - band_top, size.x * 0.42)
|
||||
Style.glyph(self, card, Vector2(size.x / 2, (band_top + band_bottom) / 2), gsize)
|
||||
draw_rect(box, Color(0.06, 0.06, 0.09, 0.67))
|
||||
var max_lines := maxi(1, int((box.size.y - 6) / Style.FONT.get_height(tsize))) # große Schrift: lieber kürzen als überlaufen
|
||||
draw_multiline_string(Style.FONT, Vector2(box.position.x + 4, box.position.y + 4 + Style.FONT.get_ascent(tsize)),
|
||||
card.text(), HORIZONTAL_ALIGNMENT_LEFT, box.size.x - 8, tsize, max_lines, Style.TEXT)
|
||||
# Werte
|
||||
Style.text(self, str(card.attack), f_stat, Style.YELLOW, Vector2(10, size.y - 6), "bottomleft", true)
|
||||
Style.text(self, str(card.health), f_stat, Style.RED, Vector2(size.x - 10, size.y - 6), "bottomright", true)
|
||||
if size.y < 90:
|
||||
_draw_compact(rect, frame, seed)
|
||||
else:
|
||||
_draw_full(rect, frame, seed)
|
||||
if dim:
|
||||
draw_rect(rect, Color(0, 0, 0, 0.47))
|
||||
if has_focus():
|
||||
Style.border(self, rect, Style.GOLD, 4, 8)
|
||||
|
||||
|
||||
## Volle Karte: Laden, Sammlung, Booster, Vorschau.
|
||||
func _draw_full(rect: Rect2, frame: Color, seed: int) -> void:
|
||||
var big := size.x >= 180
|
||||
var mid := size.x >= 140
|
||||
var f_name := 17 if big else (14 if mid else 11)
|
||||
var f_text := 13 if big else (11 if mid else 10)
|
||||
var f_stat := 20 if big else (17 if mid else 14)
|
||||
var r_cost := 17.0 if big else (14.0 if mid else 12.0)
|
||||
var r_stat := 18.0 if big else (15.0 if mid else 12.0)
|
||||
var icon := 11.0 if big else (9.0 if mid else 7.0)
|
||||
# Bild: das Elementsymbol füllt den oberen Teil
|
||||
var band_top: float = size.y * 0.36
|
||||
Style.glyph(self, card, Vector2(size.x / 2, band_top * 0.56), minf(size.x * 0.62, band_top * 0.95), 0.4)
|
||||
Style.rarity_sheen(self, rect, rarity, seed)
|
||||
# Namensband über die volle Breite
|
||||
var band_h: float = Style.fs(f_name) + 10
|
||||
var band := Rect2(0, band_top, size.x, band_h)
|
||||
draw_rect(band, Color(0.05, 0.05, 0.08, 0.82))
|
||||
var nf := Style.fit_size(card.title(), true, f_name, size.x - 12)
|
||||
Style.text(self, Style.fit(card.title(), true, Style.fs(nf), size.x - 12), nf, Style.TEXT, Vector2(size.x / 2, band.get_center().y), "center", true)
|
||||
var y := band.end.y + 4
|
||||
# Kombo eines verschmolzenen Wesens
|
||||
if card.is_combo():
|
||||
Style.text(self, tr(card.combo()), f_text, Color("e6e6e6"), Vector2(size.x / 2, y), "midtop")
|
||||
y += Style.fs(f_text) + 4
|
||||
# Schlüsselwörter als Symbole, auf großen Karten mit Wort
|
||||
var kws: Array[String] = []
|
||||
for k in Cards.KEYWORDS:
|
||||
if k in card.keywords:
|
||||
kws.append(k)
|
||||
if not kws.is_empty():
|
||||
var with_words := big
|
||||
var widths: Array[float] = []
|
||||
var total := 0.0
|
||||
for k in kws:
|
||||
var w: float = icon * 2 + 6 + (Style.FONT.get_string_size(tr(k), HORIZONTAL_ALIGNMENT_LEFT, -1, Style.fs(f_text)).x + 8 if with_words else 0)
|
||||
widths.append(w)
|
||||
total += w + 6
|
||||
if with_words and total > size.x - 12:
|
||||
with_words = false
|
||||
total = kws.size() * (icon * 2 + 12)
|
||||
var x := (size.x - total + 6) / 2
|
||||
for i in kws.size():
|
||||
var k := kws[i]
|
||||
Style.keyword_icon(self, k, Vector2(x + icon, y + icon + 2), icon)
|
||||
if with_words:
|
||||
Style.text(self, tr(k), f_text, Style.TEXT, Vector2(x + icon * 2 + 6, y + icon + 2), "midleft")
|
||||
x += widths[i] + 6
|
||||
else:
|
||||
x += icon * 2 + 12
|
||||
y += icon * 2 + 8
|
||||
# Effekttext: so hoch wie nötig, endet über den Wertkreisen
|
||||
var box := Rect2()
|
||||
var fx := card.effect_text()
|
||||
var box_bottom: float = size.y - r_stat * 2 - 4
|
||||
if fx != "" and box_bottom - y > Style.fs(f_text) + 6:
|
||||
var tsize := Style.fs(f_text)
|
||||
var heading := big
|
||||
var needed: float = Style.FONT.get_multiline_string_size(fx, HORIZONTAL_ALIGNMENT_LEFT, size.x - 20, tsize).y + 8 + (tsize + 2 if heading else 0)
|
||||
var box_top: float = maxf(y, y + (box_bottom - y - needed) / 2)
|
||||
box = Rect2(6, box_top, size.x - 12, box_bottom - box_top)
|
||||
draw_rect(box, Color(0.06, 0.06, 0.09, 0.72))
|
||||
var ty := box.position.y + 4
|
||||
if heading:
|
||||
Style.text(self, tr("Beim Ausspielen"), f_text - 2, Style.MUTED, Vector2(box.position.x + 4, ty), "topleft")
|
||||
ty += tsize + 2
|
||||
var max_lines := maxi(1, int((box.end.y - ty - 2) / Style.FONT.get_height(tsize)))
|
||||
draw_multiline_string(Style.FONT, Vector2(box.position.x + 4, ty + Style.FONT.get_ascent(tsize)),
|
||||
fx, HORIZONTAL_ALIGNMENT_LEFT, box.size.x - 8, tsize, max_lines, Style.TEXT)
|
||||
# Werte springen aus den unteren Ecken, dazwischen der Edelstein
|
||||
Style.stat_circle(self, Vector2(r_stat - 2, size.y - r_stat + 2), r_stat, str(card.attack), Style.AMBER, f_stat)
|
||||
Style.stat_circle(self, Vector2(size.x - r_stat + 2, size.y - r_stat + 2), r_stat, str(card.health), Style.CRIMSON, f_stat)
|
||||
if bonus > 0:
|
||||
Style.text_outlined(self, "+%d" % bonus, f_text, Style.GREEN, Vector2(r_stat * 2 + 4, size.y - r_stat + 2), "midleft", 3)
|
||||
Style.rarity_gem(self, rarity, Vector2(size.x / 2, size.y - r_stat + 1), 8 if big else 6, seed)
|
||||
Style.border(self, rect, frame, 3 if big else 2, 8)
|
||||
Style.cost_crystal(self, Vector2(r_cost + 2, r_cost + 2), r_cost, card.cost, f_stat)
|
||||
if tag != "":
|
||||
_draw_tag(Vector2(size.x - 6, 6), f_text - 1)
|
||||
Style.rarity_sparkle(self, rect, rarity, seed, box)
|
||||
|
||||
|
||||
## Flache Handkachel: Kosten, Name, Symbole, Werte.
|
||||
func _draw_compact(rect: Rect2, frame: Color, seed: int) -> void:
|
||||
Style.rarity_sheen(self, rect, rarity, seed)
|
||||
Style.border(self, rect, frame, 2, 8)
|
||||
Style.cost_crystal(self, Vector2(13, 13), 11, card.cost, 13)
|
||||
var name_w: float = size.x - 30 - (12 if rarity != "gewöhnlich" else 0)
|
||||
var nf := Style.fit_size(card.title(), true, 12, name_w)
|
||||
Style.text(self, Style.fit(card.title(), true, Style.fs(nf), name_w), nf, Style.TEXT, Vector2(28, 13), "midleft", true)
|
||||
Style.rarity_gem(self, rarity, Vector2(size.x - 9, 13), 5, seed)
|
||||
if tag != "":
|
||||
var w := Style.FONT_BOLD.get_string_size(tr(tag), HORIZONTAL_ALIGNMENT_LEFT, -1, Style.fs(9)).x + 12
|
||||
_draw_tag(Vector2(size.x / 2 + w / 2, size.y - 21), 9)
|
||||
else:
|
||||
var kws: Array[String] = []
|
||||
for k in Cards.KEYWORDS:
|
||||
if k in card.keywords:
|
||||
kws.append(k)
|
||||
var x := size.x / 2 - (kws.size() * 18 - 4) / 2.0
|
||||
for k in kws:
|
||||
Style.keyword_icon(self, k, Vector2(x + 6, size.y - 13), 6)
|
||||
x += 18
|
||||
Style.stat_circle(self, Vector2(11, size.y - 11), 10, str(card.attack), Style.AMBER, 12)
|
||||
Style.stat_circle(self, Vector2(size.x - 11, size.y - 11), 10, str(card.health), Style.CRIMSON, 12)
|
||||
if bonus > 0:
|
||||
Style.text_outlined(self, "+%d" % bonus, 10, Style.GREEN, Vector2(4, size.y - 29), "midleft", 3)
|
||||
Style.rarity_sparkle(self, rect, rarity, seed)
|
||||
|
||||
|
||||
## Goldenes Schild mit der Feldkombo, rechts oben.
|
||||
func _draw_tag(top_right: Vector2, font: int) -> void:
|
||||
var w := Style.FONT_BOLD.get_string_size(tr(tag), HORIZONTAL_ALIGNMENT_LEFT, -1, Style.fs(font)).x + 12
|
||||
var h := Style.fs(font) + 6
|
||||
var r := Rect2(top_right - Vector2(w, 0), Vector2(w, h))
|
||||
draw_style_box(Style.box(Color("14141c"), 6, Style.GOLD, 1), r)
|
||||
Style.text(self, tr(tag), font, Style.GOLD, r.get_center(), "center", true)
|
||||
|
||||
Reference in New Issue
Block a user