init game files
This commit is contained in:
238
scripts/ui/HandDisplay.gd
Normal file
238
scripts/ui/HandDisplay.gd
Normal file
@@ -0,0 +1,238 @@
|
||||
class_name HandDisplay
|
||||
extends Control
|
||||
|
||||
## HandDisplay - Shows the current player's hand in a fan layout
|
||||
|
||||
signal card_selected(card_instance: CardInstance)
|
||||
signal card_hovered(card_instance: CardInstance)
|
||||
signal card_unhovered
|
||||
|
||||
# Hand card visuals
|
||||
var hand_cards: Array[Control] = []
|
||||
var card_instances: Array[CardInstance] = []
|
||||
|
||||
# Layout settings
|
||||
const CARD_WIDTH: float = 100.0
|
||||
const CARD_HEIGHT: float = 140.0
|
||||
const CARD_OVERLAP: float = 70.0
|
||||
const FAN_ANGLE: float = 2.0 # Degrees per card from center
|
||||
const HOVER_LIFT: float = 25.0
|
||||
|
||||
# Current hover state
|
||||
var hovered_card_index: int = -1
|
||||
|
||||
func _ready() -> void:
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
# Connect to resized signal to re-layout when size changes
|
||||
resized.connect(_on_resized)
|
||||
|
||||
func _on_resized() -> void:
|
||||
_layout_cards()
|
||||
|
||||
## Update hand display with cards
|
||||
func update_hand(cards: Array) -> void:
|
||||
# Clear existing
|
||||
for card_ui in hand_cards:
|
||||
card_ui.queue_free()
|
||||
hand_cards.clear()
|
||||
card_instances.clear()
|
||||
|
||||
# Store card instances
|
||||
for card in cards:
|
||||
if card is CardInstance:
|
||||
card_instances.append(card)
|
||||
|
||||
# Create card UI elements
|
||||
_create_card_visuals()
|
||||
|
||||
# Defer layout to ensure size is set
|
||||
call_deferred("_layout_cards")
|
||||
|
||||
func _create_card_visuals() -> void:
|
||||
for i in range(card_instances.size()):
|
||||
var card = card_instances[i]
|
||||
var card_ui = _create_card_ui(card, i)
|
||||
add_child(card_ui)
|
||||
hand_cards.append(card_ui)
|
||||
|
||||
func _create_card_ui(card: CardInstance, index: int) -> Control:
|
||||
# Use Panel for better input handling
|
||||
var container = Panel.new()
|
||||
container.custom_minimum_size = Vector2(CARD_WIDTH, CARD_HEIGHT)
|
||||
container.size = Vector2(CARD_WIDTH, CARD_HEIGHT)
|
||||
container.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
|
||||
# Style the panel with element color
|
||||
var style = StyleBoxFlat.new()
|
||||
style.bg_color = _get_element_color(card.card_data.get_primary_element())
|
||||
style.border_color = Color.BLACK
|
||||
style.set_border_width_all(2)
|
||||
container.add_theme_stylebox_override("panel", style)
|
||||
|
||||
# Card background (keep for highlighting)
|
||||
var bg = ColorRect.new()
|
||||
bg.size = Vector2(CARD_WIDTH, CARD_HEIGHT)
|
||||
bg.color = _get_element_color(card.card_data.get_primary_element())
|
||||
bg.mouse_filter = Control.MOUSE_FILTER_IGNORE # Let parent handle input
|
||||
container.add_child(bg)
|
||||
|
||||
# Card name
|
||||
var name_label = Label.new()
|
||||
name_label.text = card.card_data.name
|
||||
name_label.position = Vector2(5, 5)
|
||||
name_label.size = Vector2(CARD_WIDTH - 10, 50)
|
||||
name_label.add_theme_font_size_override("font_size", 11)
|
||||
name_label.add_theme_color_override("font_color", Color.BLACK)
|
||||
name_label.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||
name_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
container.add_child(name_label)
|
||||
|
||||
# Cost indicator (top right)
|
||||
var cost_bg = ColorRect.new()
|
||||
cost_bg.size = Vector2(28, 28)
|
||||
cost_bg.position = Vector2(CARD_WIDTH - 32, 4)
|
||||
cost_bg.color = Color(0.2, 0.2, 0.2)
|
||||
cost_bg.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
container.add_child(cost_bg)
|
||||
|
||||
var cost_label = Label.new()
|
||||
cost_label.text = str(card.card_data.cost)
|
||||
cost_label.position = Vector2(CARD_WIDTH - 32, 4)
|
||||
cost_label.size = Vector2(28, 28)
|
||||
cost_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
cost_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
cost_label.add_theme_font_size_override("font_size", 16)
|
||||
cost_label.add_theme_color_override("font_color", Color.WHITE)
|
||||
cost_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
container.add_child(cost_label)
|
||||
|
||||
# Type indicator (bottom left)
|
||||
var type_label = Label.new()
|
||||
type_label.text = Enums.card_type_to_string(card.card_data.type)
|
||||
type_label.position = Vector2(5, CARD_HEIGHT - 22)
|
||||
type_label.add_theme_font_size_override("font_size", 10)
|
||||
type_label.add_theme_color_override("font_color", Color.BLACK)
|
||||
type_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
container.add_child(type_label)
|
||||
|
||||
# Power for forwards (bottom right)
|
||||
if card.card_data.type == Enums.CardType.FORWARD:
|
||||
var power_bg = ColorRect.new()
|
||||
power_bg.size = Vector2(45, 20)
|
||||
power_bg.position = Vector2(CARD_WIDTH - 50, CARD_HEIGHT - 24)
|
||||
power_bg.color = Color(0.3, 0.1, 0.1, 0.8)
|
||||
power_bg.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
container.add_child(power_bg)
|
||||
|
||||
var power_label = Label.new()
|
||||
power_label.text = str(card.card_data.power)
|
||||
power_label.position = Vector2(CARD_WIDTH - 50, CARD_HEIGHT - 24)
|
||||
power_label.size = Vector2(45, 20)
|
||||
power_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
power_label.add_theme_font_size_override("font_size", 12)
|
||||
power_label.add_theme_color_override("font_color", Color.WHITE)
|
||||
power_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
container.add_child(power_label)
|
||||
|
||||
# Connect signals
|
||||
container.gui_input.connect(_on_card_gui_input.bind(index))
|
||||
container.mouse_entered.connect(_on_card_mouse_entered.bind(index))
|
||||
container.mouse_exited.connect(_on_card_mouse_exited.bind(index))
|
||||
|
||||
return container
|
||||
|
||||
func _get_element_color(element: Enums.Element) -> Color:
|
||||
var color = Enums.get_element_color(element)
|
||||
# Lighten for card background
|
||||
return color.lightened(0.4)
|
||||
|
||||
func _layout_cards() -> void:
|
||||
var card_count = hand_cards.size()
|
||||
if card_count == 0:
|
||||
return
|
||||
|
||||
# Get actual display width - use size if available, otherwise viewport
|
||||
var display_width = size.x
|
||||
|
||||
if display_width <= 0:
|
||||
var viewport = get_viewport()
|
||||
if viewport:
|
||||
display_width = viewport.get_visible_rect().size.x - 100 # Leave margins
|
||||
|
||||
if display_width <= 0:
|
||||
display_width = 1820 # Fallback
|
||||
|
||||
# Calculate total width needed
|
||||
var total_width = CARD_WIDTH + (card_count - 1) * CARD_OVERLAP
|
||||
var start_x = (display_width - total_width) / 2.0
|
||||
|
||||
# Position each card
|
||||
for i in range(card_count):
|
||||
var card_ui = hand_cards[i]
|
||||
|
||||
# X position with overlap
|
||||
var x = start_x + i * CARD_OVERLAP
|
||||
|
||||
# Y position (near top of container, with hover lift)
|
||||
var y = 10.0
|
||||
if i == hovered_card_index:
|
||||
y -= HOVER_LIFT
|
||||
|
||||
# Rotation based on position in fan
|
||||
var center_offset = i - (card_count - 1) / 2.0
|
||||
var angle = center_offset * FAN_ANGLE
|
||||
|
||||
card_ui.position = Vector2(x, y)
|
||||
card_ui.rotation = deg_to_rad(angle)
|
||||
card_ui.z_index = i
|
||||
if i == hovered_card_index:
|
||||
card_ui.z_index = 100
|
||||
|
||||
func _on_card_gui_input(event: InputEvent, index: int) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
|
||||
print("HandDisplay: Card clicked, index=", index)
|
||||
if index >= 0 and index < card_instances.size():
|
||||
print("HandDisplay: Emitting card_selected for ", card_instances[index].card_data.name)
|
||||
card_selected.emit(card_instances[index])
|
||||
|
||||
func _on_card_mouse_entered(index: int) -> void:
|
||||
hovered_card_index = index
|
||||
_layout_cards()
|
||||
if index >= 0 and index < card_instances.size():
|
||||
card_hovered.emit(card_instances[index])
|
||||
|
||||
func _on_card_mouse_exited(index: int) -> void:
|
||||
if hovered_card_index == index:
|
||||
hovered_card_index = -1
|
||||
_layout_cards()
|
||||
card_unhovered.emit()
|
||||
|
||||
## Highlight playable cards
|
||||
func highlight_playable(predicate: Callable) -> void:
|
||||
for i in range(hand_cards.size()):
|
||||
var card_ui = hand_cards[i]
|
||||
var card = card_instances[i]
|
||||
|
||||
var bg = card_ui.get_child(0) as ColorRect
|
||||
if bg:
|
||||
if predicate.call(card):
|
||||
# Add glow effect - brighter
|
||||
bg.color = _get_element_color(card.card_data.get_primary_element()).lightened(0.2)
|
||||
else:
|
||||
# Dim non-playable
|
||||
bg.color = _get_element_color(card.card_data.get_primary_element()).darkened(0.4)
|
||||
|
||||
## Clear all highlights
|
||||
func clear_highlights() -> void:
|
||||
for i in range(hand_cards.size()):
|
||||
var card_ui = hand_cards[i]
|
||||
var card = card_instances[i]
|
||||
|
||||
var bg = card_ui.get_child(0) as ColorRect
|
||||
if bg:
|
||||
bg.color = _get_element_color(card.card_data.get_primary_element())
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_RESIZED:
|
||||
_layout_cards()
|
||||
Reference in New Issue
Block a user