Untitled
unknown
plain_text
a month ago
5.3 kB
12
Indexable
extends Control
class_name CardsHand
@export var card_scene: PackedScene
@export var fan_max_angle_deg: float = 30.0
@export var fan_radius: float = 260.0
@export var fan_spacing: float = 140.0
@export var bottom_padding: float = 40.0
@export var fly_in_offset_y: float = 300.0
@export var fly_in_duration: float = 0.45
@export var fly_in_stagger: float = 0.06
@export var fly_out_offset: Vector2 = Vector2(900.0, 500.0)
@export var fly_out_duration: float = 0.35
@export var fly_out_stagger: float = 0.04
@export var fly_out_extra_rotation_deg: float = 18.0
var _card_targets: Dictionary = {}
var _suppress_reflow: bool = false
func init() -> void:
pass
func get_cards_data() -> Array[CardData]:
var out: Array[CardData] = []
for child in get_children():
var card := child as IngameCard
if card != null:
out.append(card.card_data)
return out
func _on_card_tree_exited() -> void:
if _suppress_reflow:
return
call_deferred("reflow_fan")
func reflow_fan() -> void:
var list: Array[IngameCard] = []
for c in get_children():
var ic := c as IngameCard
if ic != null:
list.append(ic)
var count: int = list.size()
if count == 0:
_card_targets.clear()
return
var pivot: Vector2 = size * 0.5
var center_index: float = (count - 1) * 0.5
var max_index_dist: float = max(1.0, center_index)
for i in count:
var card_node: IngameCard = list[i]
var t: float = (float(i) - center_index) / max_index_dist
var angle_rad: float = deg_to_rad(fan_max_angle_deg) * t
var x: float = t * fan_spacing * center_index
var y: float = fan_radius * (1.0 - cos(angle_rad)) + bottom_padding
card_node.pivot_offset = Vector2(card_node.size.x * 0.5, card_node.size.y)
var pivot_pos: Vector2 = pivot + Vector2(x, y)
var pos: Vector2 = pivot_pos - card_node.pivot_offset
_card_targets[card_node] = {"pos": pos, "rot": angle_rad}
card_node.set_rest_pose(pos, angle_rad)
var dnd := card_node.get_node_or_null("DragNDropFeature") as DragNDropFeature
if dnd != null and not dnd.is_dragging():
if dnd.is_peeking():
card_node.z_index = dnd.z_index_peek
else:
card_node.z_index = i
card_node.apply_layout_from_hand(true)
func set_cards(cards: Array[CardData]) -> void:
_suppress_reflow = true
for child in get_children():
remove_child(child)
child.free()
_card_targets.clear()
_suppress_reflow = false
if cards.is_empty():
return
var pivot: Vector2 = size * 0.5
var count: int = cards.size()
var center_index: float = (count - 1) * 0.5
var max_index_dist: float = max(1.0, center_index)
for i in count:
var card_node := card_scene.instantiate() as IngameCard
add_child(card_node)
card_node.tree_exited.connect(_on_card_tree_exited)
card_node.init(cards[i])
var t: float = (float(i) - center_index) / max_index_dist
var angle_rad: float = deg_to_rad(fan_max_angle_deg) * t
var x: float = t * fan_spacing * center_index
var y: float = fan_radius * (1.0 - cos(angle_rad)) + bottom_padding
card_node.pivot_offset = Vector2(card_node.size.x * 0.5, card_node.size.y)
var pivot_pos: Vector2 = pivot + Vector2(x, y)
var target_pos: Vector2 = pivot_pos - card_node.pivot_offset
_card_targets[card_node] = {
"pos": target_pos,
"rot": angle_rad,
}
card_node.configure_hand(self, target_pos, angle_rad)
card_node.z_index = i
card_node.visible = false
card_node.position = Vector2(pivot_pos.x, pivot_pos.y + fly_in_offset_y) - card_node.pivot_offset
card_node.rotation = angle_rad * 0.35
func launch_start_turn_animation() -> void:
var i: int = 0
for child in get_children():
var card := child as IngameCard
if card == null:
continue
if not _card_targets.has(card):
continue
var target_dict: Dictionary = _card_targets[card]
var target_pos: Vector2 = target_dict["pos"]
var target_rot: float = target_dict["rot"]
card.visible = true
var tween := create_tween()
tween.set_trans(Tween.TRANS_BACK)
tween.set_ease(Tween.EASE_OUT)
if i > 0 and fly_in_stagger > 0.0:
tween.tween_interval(float(i) * fly_in_stagger)
tween.tween_property(card, "position", target_pos, fly_in_duration)
tween.parallel().tween_property(card, "rotation", target_rot, fly_in_duration)
i += 1
func launch_end_turn_animation() -> void:
var cards: Array[IngameCard] = []
for child in get_children():
var card := child as IngameCard
if card != null:
cards.append(card)
if cards.is_empty():
_card_targets.clear()
return
for c in cards:
if c.tree_exited.is_connected(_on_card_tree_exited):
c.tree_exited.disconnect(_on_card_tree_exited)
for idx in cards.size():
var card := cards[idx]
card.set_interactive(false)
var tween := create_tween()
tween.set_trans(Tween.TRANS_QUAD)
tween.set_ease(Tween.EASE_IN)
if idx > 0 and fly_out_stagger > 0.0:
tween.tween_interval(float(idx) * fly_out_stagger)
tween.tween_property(card, "position", card.position + fly_out_offset, fly_out_duration)
tween.parallel().tween_property(
card,
"rotation",
card.rotation + deg_to_rad(fly_out_extra_rotation_deg),
fly_out_duration
)
tween.tween_callback(Callable(card, "queue_free"))
_card_targets.clear()
Editor is loading...
Leave a Comment