hand show and hide

This commit is contained in:
2026-01-27 19:09:55 -05:00
parent 7a89ee47f0
commit 8b5a7b1989
5 changed files with 241 additions and 29 deletions

View File

@@ -82,6 +82,7 @@ func _setup_ui() -> void:
hand_display.card_hovered.connect(_on_hand_card_hovered)
hand_display.card_unhovered.connect(_on_hand_card_unhovered)
hand_display.card_selected.connect(_on_hand_card_selected)
hand_display.hand_minimized_changed.connect(_on_hand_minimized_changed)
# Create damage displays (positioned by 3D camera overlay later)
for i in range(2):
@@ -89,18 +90,25 @@ func _setup_ui() -> void:
damage_displays.append(damage_display)
func _position_hand_display() -> void:
# Get viewport size and position hand at bottom
var viewport = get_viewport()
if viewport:
# get_visible_rect() gives the coordinate space for 2D content
# With canvas_items + expand, this is the expanded design space
var vp_size = viewport.get_visible_rect().size
# Hand cards are 195x273px (triple original), positioned at y=0 in container
var card_height = 273.0
var hand_height = card_height + 25.0 # Extra space for hover lift
var is_min = hand_display and hand_display.is_minimized
# Position so card bottom is 100px above viewport bottom
var bottom_offset = 100.0
hand_display.position = Vector2(10, vp_size.y - bottom_offset - card_height)
hand_display.size = Vector2(vp_size.x - 20, hand_height)
var card_height = 273.0
if is_min:
# Minimized: push cards down so only the top portion peeks up
var peek_height = 65.0 # How much of the card top is visible
hand_display.position = Vector2(10, vp_size.y - peek_height)
hand_display.size = Vector2(vp_size.x - 20, card_height + 25.0)
else:
# Full hand: cards at the bottom of the screen
var hand_height = card_height + 25.0 # Extra space for hover lift
var bottom_offset = 10.0
hand_display.position = Vector2(10, vp_size.y - bottom_offset - card_height)
hand_display.size = Vector2(vp_size.x - 20, hand_height)
if not viewport.size_changed.is_connected(_on_viewport_resized):
viewport.size_changed.connect(_on_viewport_resized)
@@ -108,12 +116,10 @@ func _position_hand_display() -> void:
func _on_viewport_resized() -> void:
var viewport = get_viewport()
if viewport and hand_display:
var vp_size = viewport.get_visible_rect().size
var card_height = 273.0 # Triple size hand cards
var hand_height = card_height + 25.0
var bottom_offset = 100.0
hand_display.position = Vector2(10, vp_size.y - bottom_offset - card_height)
hand_display.size = Vector2(vp_size.x - 20, hand_height)
_position_hand_display()
func _on_hand_minimized_changed(_minimized: bool) -> void:
_position_hand_display()
func _connect_signals() -> void:
# GameManager signals

View File

@@ -8,6 +8,7 @@ signal card_action_requested(card_instance: CardInstance, action: String)
signal card_hovered(card_instance: CardInstance)
signal card_unhovered
signal card_selected(card_instance: CardInstance) # Emitted when selection panel opens
signal hand_minimized_changed(minimized: bool) # Emitted when minimize state changes
# Hand card visuals
var hand_cards: Array[Control] = []
@@ -32,6 +33,14 @@ var selected_card_panel: Panel = null
var card_image_container: Control = null
var action_menu: VBoxContainer = null
# Minimized hand state
var is_minimized: bool = false
var minimized_bar: HBoxContainer = null
var minimized_items: Array = []
var toggle_button: Button = null
const MINIMIZED_BAR_HEIGHT: float = 30.0
const MINIMIZED_ITEM_GAP: float = 4.0
# Debug visualization (set to true to see positioning markers)
const DEBUG_MARKERS: bool = false
var debug_container_outline: ColorRect = null
@@ -41,6 +50,8 @@ func _ready() -> void:
clip_contents = false # Allow cards to extend beyond container bounds
resized.connect(_on_resized)
_create_selection_ui()
_create_toggle_button()
_create_minimized_bar()
if DEBUG_MARKERS:
_create_debug_markers()
@@ -91,6 +102,175 @@ func _create_selection_ui() -> void:
selected_card_panel.size = Vector2(panel_width, panel_height)
func _create_toggle_button() -> void:
toggle_button = Button.new()
toggle_button.text = "Hide Hand"
toggle_button.custom_minimum_size = Vector2(90, 26)
toggle_button.size = Vector2(90, 26)
toggle_button.mouse_filter = Control.MOUSE_FILTER_STOP
toggle_button.z_index = 150
toggle_button.add_theme_font_size_override("font_size", 11)
toggle_button.add_theme_color_override("font_color", Color(0.8, 0.75, 0.65))
toggle_button.add_theme_color_override("font_hover_color", Color(1.0, 0.95, 0.8))
var style_normal = StyleBoxFlat.new()
style_normal.bg_color = Color(0.12, 0.12, 0.16, 0.85)
style_normal.border_color = Color(0.4, 0.35, 0.25)
style_normal.set_border_width_all(1)
style_normal.set_corner_radius_all(4)
toggle_button.add_theme_stylebox_override("normal", style_normal)
var style_hover = StyleBoxFlat.new()
style_hover.bg_color = Color(0.18, 0.18, 0.24, 0.9)
style_hover.border_color = Color(0.6, 0.5, 0.3)
style_hover.set_border_width_all(1)
style_hover.set_corner_radius_all(4)
toggle_button.add_theme_stylebox_override("hover", style_hover)
var style_pressed = StyleBoxFlat.new()
style_pressed.bg_color = Color(0.08, 0.08, 0.1, 0.9)
style_pressed.border_color = Color(0.6, 0.5, 0.3)
style_pressed.set_border_width_all(1)
style_pressed.set_corner_radius_all(4)
toggle_button.add_theme_stylebox_override("pressed", style_pressed)
toggle_button.pressed.connect(_on_toggle_hand)
add_child(toggle_button)
func _create_minimized_bar() -> void:
minimized_bar = HBoxContainer.new()
minimized_bar.visible = false
minimized_bar.mouse_filter = Control.MOUSE_FILTER_IGNORE
minimized_bar.add_theme_constant_override("separation", int(MINIMIZED_ITEM_GAP))
minimized_bar.z_index = 10
add_child(minimized_bar)
func _on_toggle_hand() -> void:
is_minimized = not is_minimized
if is_minimized:
toggle_button.text = "Show Hand"
_deselect_card()
# Cards stay visible — Main.gd will reposition so only tops peek up
else:
toggle_button.text = "Hide Hand"
_layout_cards()
_position_toggle_button()
hand_minimized_changed.emit(is_minimized)
func _update_minimized_bar() -> void:
# Clear previous items
for child in minimized_bar.get_children():
child.queue_free()
minimized_items.clear()
for i in range(card_instances.size()):
var card = card_instances[i]
var item = _create_minimized_item(card, i)
minimized_bar.add_child(item)
minimized_items.append(item)
# Position the bar centered at the bottom
call_deferred("_position_minimized_bar")
func _create_minimized_item(card: CardInstance, index: int) -> PanelContainer:
var item = PanelContainer.new()
item.mouse_filter = Control.MOUSE_FILTER_STOP
var style = StyleBoxFlat.new()
style.bg_color = Color(0.1, 0.1, 0.14, 0.9)
style.border_color = Color(0.3, 0.3, 0.35)
style.set_border_width_all(1)
style.set_corner_radius_all(3)
style.content_margin_left = 4
style.content_margin_right = 8
style.content_margin_top = 2
style.content_margin_bottom = 2
item.add_theme_stylebox_override("panel", style)
var hbox = HBoxContainer.new()
hbox.add_theme_constant_override("separation", 5)
hbox.mouse_filter = Control.MOUSE_FILTER_IGNORE
item.add_child(hbox)
# Cost crystal — element-colored circle with cost number
var crystal = Panel.new()
crystal.custom_minimum_size = Vector2(22, 22)
crystal.mouse_filter = Control.MOUSE_FILTER_IGNORE
var crystal_style = StyleBoxFlat.new()
var elem_color = Enums.get_element_color(card.card_data.get_primary_element())
crystal_style.bg_color = elem_color
crystal_style.set_corner_radius_all(11)
crystal_style.set_border_width_all(1)
crystal_style.border_color = elem_color.lightened(0.3)
crystal.add_theme_stylebox_override("panel", crystal_style)
var cost_label = Label.new()
cost_label.text = str(card.card_data.cost)
cost_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
cost_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
cost_label.set_anchors_preset(Control.PRESET_FULL_RECT)
cost_label.add_theme_font_size_override("font_size", 12)
cost_label.add_theme_color_override("font_color", Color.WHITE)
cost_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
crystal.add_child(cost_label)
hbox.add_child(crystal)
# Card name
var name_label = Label.new()
name_label.text = card.card_data.name
name_label.add_theme_font_size_override("font_size", 12)
name_label.add_theme_color_override("font_color", Color(0.85, 0.82, 0.72))
name_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
hbox.add_child(name_label)
# Click to expand hand and select this card
item.gui_input.connect(_on_minimized_item_input.bind(index))
return item
func _on_minimized_item_input(event: InputEvent, index: int) -> void:
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
# Expand hand and select the clicked card
is_minimized = false
toggle_button.text = "Hide Hand"
minimized_bar.visible = false
for card_ui in hand_cards:
card_ui.visible = true
_layout_cards()
_position_toggle_button()
hand_minimized_changed.emit(false)
_select_card(index)
func _position_toggle_button() -> void:
if not toggle_button:
return
var display_width = size.x
if display_width <= 0:
var viewport = get_viewport()
if viewport:
display_width = viewport.get_visible_rect().size.x - 20
# Position toggle button: right side, above hand area
if is_minimized:
# Above the minimized bar
toggle_button.position = Vector2(display_width - toggle_button.size.x - 5, -toggle_button.size.y - 4)
else:
# Above the full hand
toggle_button.position = Vector2(display_width - toggle_button.size.x - 5, -toggle_button.size.y - 4)
func _position_minimized_bar() -> void:
if not minimized_bar:
return
var display_width = size.x
if display_width <= 0:
var viewport = get_viewport()
if viewport:
display_width = viewport.get_visible_rect().size.x - 20
# Center the bar horizontally, positioned at top of hand container area
var bar_width = minimized_bar.size.x
minimized_bar.position = Vector2((display_width - bar_width) / 2.0, 0)
func _create_debug_markers() -> void:
# Create a visible outline around the hand container bounds
# RED = hand container area
@@ -162,6 +342,8 @@ func update_hand(cards: Array) -> void:
# Create card UI elements
_create_card_visuals()
# Cards stay visible even when minimized — Main.gd handles positioning
# Defer layout to ensure size is set
call_deferred("_layout_cards")
@@ -234,6 +416,8 @@ func _get_element_color(element: Enums.Element) -> Color:
return color.lightened(0.4)
func _layout_cards() -> void:
_position_toggle_button()
var card_count = hand_cards.size()
if card_count == 0:
return
@@ -258,8 +442,8 @@ func _layout_cards() -> void:
var x = start_x + i * CARD_OVERLAP
var y = base_y
# Lift hovered card slightly
if i == hovered_card_index and selected_card_index == -1:
# Lift hovered card slightly (not when minimized)
if i == hovered_card_index and selected_card_index == -1 and not is_minimized:
y -= HOVER_LIFT # Lift by 15px
# Dim selected card in hand
@@ -281,7 +465,15 @@ func _on_card_gui_input(event: InputEvent, index: int) -> void:
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
if index >= 0 and index < card_instances.size():
if selected_card_index == index:
if is_minimized:
# Clicking a peeking card expands the hand and selects it
is_minimized = false
toggle_button.text = "Hide Hand"
hand_minimized_changed.emit(false)
_layout_cards()
_position_toggle_button()
_select_card(index)
elif selected_card_index == index:
_deselect_card()
else:
_select_card(index)