110 lines
4.8 KiB
GDScript
110 lines
4.8 KiB
GDScript
class_name CardView
|
|
extends Control
|
|
## Zeichnet eine Karte (Hand, Sammlung, Booster, Vorschau).
|
|
## Oben Kosten (links) und Name, in der Mitte das Bild im Kreis, unten Angriff (links) und
|
|
## Leben (rechts). Die Elemente färben den Hintergrund (verschmolzen: ein Streifen je Element),
|
|
## das Bild trägt bei Verschmelzungen der stärkere Elternteil; die Seltenheit steckt in Name,
|
|
## Bild, Werten und Rahmen (siehe Style).
|
|
|
|
signal clicked(view: CardView)
|
|
signal pressed(view: CardView, pos: Vector2) # nur mit drag_enabled: der Kampf macht daraus Klick oder Ziehen
|
|
signal hover(card: Cards.Card, entered: bool)
|
|
|
|
var card: Cards.Card
|
|
var border = null # Color oder null (dann Rahmen der Seltenheitsstufe)
|
|
var rarity := "Common" # nur Optik
|
|
var dim := false
|
|
var bonus := 0 # Vorschau im Kampf: Elementbonus, den die Karte offen gelegt bekäme
|
|
var lift := false # hebt sich beim Zeigen an (Hand)
|
|
var drag_enabled := false # Hand im Kampf: Drücken meldet pressed statt clicked
|
|
var drop := false # Ziel der gerade gezogenen Karte
|
|
|
|
|
|
## 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 = "Common") -> 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)
|
|
_lift(true))
|
|
mouse_exited.connect(func():
|
|
hover.emit(card, false)
|
|
_lift(false))
|
|
if focusable:
|
|
focus_mode = Control.FOCUS_ALL
|
|
focus_entered.connect(func():
|
|
hover.emit(card, true)
|
|
queue_redraw())
|
|
focus_exited.connect(func():
|
|
hover.emit(card, false)
|
|
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()
|
|
if drag_enabled:
|
|
pressed.emit(self, event.global_position)
|
|
else:
|
|
clicked.emit(self)
|
|
elif has_focus() and event.is_action_pressed("ui_accept"):
|
|
accept_event()
|
|
clicked.emit(self)
|
|
|
|
|
|
func _draw() -> void:
|
|
var rect := Rect2(Vector2.ZERO, size)
|
|
var seed := hash(card.id)
|
|
var frame: Color = border if border != null else Style.rarity_frame(rarity, seed)
|
|
if rarity != "Common":
|
|
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 big := size.x >= 180
|
|
var mid := size.x >= 140
|
|
var f_name := 17 if big else (14 if mid else 11)
|
|
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 pad := 8.0 if mid else 6.0
|
|
var shiny := Style.rarity_stats_shiny(rarity)
|
|
# Oben: Kosten links, daneben der Name; das Namensfeld ist genau so hoch wie der Kristall
|
|
var top_h := r_cost * 2 + 4
|
|
draw_rect(Rect2(2, 2, size.x - 4, top_h), Color(0.05, 0.05, 0.08, 0.6))
|
|
Style.card_name(self, card.title(), f_name, rarity, Rect2(r_cost * 2 + 10, 2, size.x - r_cost * 2 - pad - 10, top_h), seed)
|
|
# Mitte: das Bild im Kreis, so groß wie der Platz bis zu den Werten erlaubt
|
|
var pic_top := top_h + 4
|
|
var pic_bottom := size.y - r_stat - 4
|
|
var r_pic := minf(size.x * 0.42, (pic_bottom - pic_top) / 2)
|
|
Style.picture(self, card, Vector2(size.x / 2, (pic_top + pic_bottom) / 2), r_pic, rarity, seed)
|
|
# Unten: Angriff links, Leben rechts
|
|
Style.stat_circle(self, Vector2(r_stat - 2, size.y - r_stat + 2), r_stat, str(card.attack), Style.AMBER, f_stat, Color.WHITE, shiny)
|
|
Style.stat_circle(self, Vector2(size.x - r_stat + 2, size.y - r_stat + 2), r_stat, str(card.health), Style.LIFE, f_stat, Color.WHITE, shiny)
|
|
if bonus > 0:
|
|
Style.text_outlined(self, "+%d" % bonus, 13 if big else 11, Style.GREEN, Vector2(r_stat * 2 + 4, size.y - r_stat + 2), "midleft", 3)
|
|
Style.card_sheen(self, rect, rarity, seed)
|
|
Style.border(self, rect, frame, 3 if big else 2, 8)
|
|
Style.cost_crystal(self, Vector2(r_cost + 4, r_cost + 4), r_cost, card.cost, f_stat, shiny)
|
|
Style.rarity_sparkle(self, rect, rarity, seed)
|
|
if dim:
|
|
draw_rect(rect, Color(0, 0, 0, 0.47))
|
|
if has_focus():
|
|
Style.border(self, rect, Style.GOLD, 4, 8)
|
|
if drop:
|
|
Style.border(self, rect, Style.GOLD, 5, 8)
|