feat: Implement initial main game scene with player board UI, powerup inventory script, and associated assets.
This commit is contained in:
@@ -5,10 +5,17 @@ extends Control
|
||||
# PowerUpInventoryUI - Displays stored powerups and handles selection
|
||||
|
||||
# UI References
|
||||
var icon_containers: Dictionary = {} # { EffectEnum: Button }
|
||||
# UI References
|
||||
var power_up_button: Button
|
||||
var effect_textures: Dictionary = {
|
||||
0: preload("res://assets/graphics/touch_control/speed.png"),
|
||||
1: preload("res://assets/graphics/touch_control/freeze_area.png"),
|
||||
2: preload("res://assets/graphics/touch_control/wall.png"),
|
||||
3: preload("res://assets/graphics/touch_control/ghost.png")
|
||||
}
|
||||
|
||||
# Local State
|
||||
var selected_effect: int = -1
|
||||
var current_effect: int = -1
|
||||
var special_manager_ref: Node = null # Reference to SpecialTilesManager
|
||||
@onready var SettingsManager = get_node_or_null("/root/SettingsManager")
|
||||
|
||||
@@ -20,78 +27,44 @@ func _ready():
|
||||
# Connect to SettingsManager to update labels
|
||||
if SettingsManager and not SettingsManager.control_remapped.is_connected(_on_control_remapped):
|
||||
SettingsManager.control_remapped.connect(_on_control_remapped)
|
||||
# Map Effect Enum to UI Nodes (Assumes specific names in main.tscn)
|
||||
# We try to get them immediately. If they are children, they should be accessible.
|
||||
var container = get_node_or_null("Container")
|
||||
if not container:
|
||||
print("[PowerUpUI] ERROR: Container not found in ", get_path())
|
||||
return
|
||||
|
||||
# Center buttons in the container instead of spreading them out
|
||||
container.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
|
||||
# Mapping based on User Request
|
||||
# 11: FASTER_SPEED (0) -> SpeedBtn
|
||||
# 12: AREA_FREEZE (1) -> FreezeAreaBtn
|
||||
# 13: BLOCK_FLOOR (2) -> WallBtn
|
||||
# 14: INVISIBLE_MODE (3) -> GhostBtn
|
||||
|
||||
# We use 0, 1, 2, 3 to match SpecialTilesManager.SpecialEffect enum
|
||||
var speed_btn = container.get_node_or_null("SpeedBtn")
|
||||
var freeze_btn = container.get_node_or_null("FreezeAreaBtn")
|
||||
var wall_btn = container.get_node_or_null("WallBtn")
|
||||
var ghost_btn = container.get_node_or_null("GhostBtn")
|
||||
|
||||
var mode = LobbyManager.get_game_mode()
|
||||
var is_restricted = GameMode.is_restricted(mode)
|
||||
|
||||
_setup_btn(0, speed_btn)
|
||||
_setup_btn(1, freeze_btn)
|
||||
_setup_btn(2, wall_btn)
|
||||
_setup_btn(3, ghost_btn)
|
||||
# New Single Button UI
|
||||
power_up_button = get_node_or_null("PowerUpBtn")
|
||||
if not power_up_button:
|
||||
# Fallback to Container/PowerUpBtn just in case
|
||||
power_up_button = get_node_or_null("Container/PowerUpBtn")
|
||||
|
||||
if not power_up_button:
|
||||
print("[PowerUpUI] ERROR: PowerUpBtn not found")
|
||||
return
|
||||
|
||||
# Remove mode-based restrictions on visibility for now, as ownership controls visibility
|
||||
if wall_btn: wall_btn.visible = false
|
||||
if freeze_btn: freeze_btn.visible = false
|
||||
if speed_btn: speed_btn.visible = false
|
||||
if ghost_btn: ghost_btn.visible = false
|
||||
# Helper to setup the single button
|
||||
_setup_powerup_btn(power_up_button)
|
||||
|
||||
_update_shortcuts_for_mode(is_restricted)
|
||||
# Start hidden until player has a powerup
|
||||
power_up_button.visible = false
|
||||
|
||||
|
||||
print("[PowerUpUI] UI Initialization Complete. Mapped %d buttons." % icon_containers.size())
|
||||
print("[PowerUpUI] UI Initialization Complete (Single Button Mode).")
|
||||
|
||||
|
||||
func _on_control_remapped(_action: String, _key: int):
|
||||
# Refresh all labels
|
||||
_update_shortcuts_for_mode(LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO))
|
||||
|
||||
func _setup_btn(effect_id: int, btn: Button):
|
||||
if not btn:
|
||||
print("[PowerUpUI] Warning: Button for effect %d is null" % effect_id)
|
||||
return
|
||||
|
||||
icon_containers[effect_id] = btn
|
||||
|
||||
func _setup_powerup_btn(btn: Button):
|
||||
# Start DISABLED
|
||||
btn.disabled = true
|
||||
btn.modulate = Color(0.5, 0.5, 0.5, 0.5) # Grayed out
|
||||
btn.modulate = Color(0.5, 0.5, 0.5, 0.5)
|
||||
btn.focus_mode = Control.FOCUS_NONE
|
||||
|
||||
# Fix "Floating" issue: don't expand button to fill whole container height
|
||||
# This keeps the buttons grouped tightly together
|
||||
btn.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
btn.custom_minimum_size.y = 80 # Consistent height
|
||||
|
||||
|
||||
|
||||
# Add Cooldown Overlay
|
||||
if not btn.has_node("CooldownOverlay"):
|
||||
var overlay = ColorRect.new()
|
||||
overlay.name = "CooldownOverlay"
|
||||
overlay.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
overlay.color = Color(0, 0, 0, 0.6) # Semi-transparent black
|
||||
overlay.color = Color(0, 0, 0, 0.6)
|
||||
overlay.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
overlay.anchor_top = 1.0 # Start empty at bottom
|
||||
overlay.anchor_top = 1.0
|
||||
overlay.grow_vertical = Control.GROW_DIRECTION_BEGIN
|
||||
btn.add_child(overlay)
|
||||
|
||||
@@ -100,29 +73,30 @@ func _setup_btn(effect_id: int, btn: Button):
|
||||
var sc_lbl = Label.new()
|
||||
sc_lbl.name = "ShortcutLabel"
|
||||
sc_lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
sc_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||
sc_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||
sc_lbl.vertical_alignment = VERTICAL_ALIGNMENT_TOP
|
||||
sc_lbl.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
sc_lbl.offset_left = 5
|
||||
sc_lbl.offset_top = -4 # Lowered slightly from -12
|
||||
sc_lbl.set_anchors_preset(Control.PRESET_TOP_RIGHT)
|
||||
sc_lbl.offset_left = -60 # Width of label roughly
|
||||
sc_lbl.offset_right = 6
|
||||
sc_lbl.offset_top = -4
|
||||
sc_lbl.offset_bottom = 12
|
||||
sc_lbl.add_theme_font_size_override("font_size", 16)
|
||||
sc_lbl.add_theme_color_override("font_outline_color", Color.BLACK)
|
||||
sc_lbl.add_theme_constant_override("outline_size", 4)
|
||||
sc_lbl.add_theme_color_override("font_color", Color(0.9, 0.9, 0.9))
|
||||
btn.add_child(sc_lbl)
|
||||
|
||||
_update_btn_shortcut(effect_id, btn)
|
||||
_update_btn_shortcut(btn)
|
||||
|
||||
# Connect click
|
||||
if not btn.pressed.is_connected(_on_btn_pressed):
|
||||
btn.pressed.connect(_on_btn_pressed.bind(effect_id))
|
||||
btn.pressed.connect(_on_btn_pressed)
|
||||
|
||||
func _update_shortcuts_for_mode(is_restricted: bool):
|
||||
for effect_id in icon_containers:
|
||||
var btn = icon_containers[effect_id]
|
||||
_update_btn_shortcut(effect_id, btn)
|
||||
func _update_shortcuts_for_mode(_is_restricted: bool):
|
||||
if power_up_button:
|
||||
_update_btn_shortcut(power_up_button)
|
||||
|
||||
func _update_btn_shortcut(_effect_id: int, btn: Button):
|
||||
func _update_btn_shortcut(btn: Button):
|
||||
var sc_lbl = btn.get_node_or_null("ShortcutLabel")
|
||||
if not sc_lbl: return
|
||||
|
||||
@@ -130,15 +104,16 @@ func _update_btn_shortcut(_effect_id: int, btn: Button):
|
||||
sc_lbl.text = ""
|
||||
return
|
||||
|
||||
# Show only Shortcut 1 as per single-slot request
|
||||
# Show universal powerup shortcut
|
||||
sc_lbl.text = " %s " % SettingsManager.get_control_text("use_powerup")
|
||||
|
||||
func _on_btn_pressed(effect_id: int):
|
||||
print("[PowerUpUI] Clicked Button %d" % effect_id)
|
||||
func _on_btn_pressed(effect_id: int = -1):
|
||||
var target_effect = effect_id if effect_id != -1 else current_effect
|
||||
if target_effect == -1: return
|
||||
|
||||
print("[PowerUpUI] Activating effect: %d" % target_effect)
|
||||
if special_manager_ref:
|
||||
special_manager_ref.activate_effect(effect_id)
|
||||
else:
|
||||
print("[PowerUpUI] ERROR: special_manager_ref is null during click")
|
||||
special_manager_ref.activate_effect(target_effect)
|
||||
|
||||
func setup(player_node):
|
||||
print("[PowerUpUI] Setup called for player: ", player_node.name)
|
||||
@@ -160,28 +135,25 @@ func _on_player_child_entered(node: Node, player_node: Node):
|
||||
player_node.child_entered_tree.disconnect(_on_player_child_entered)
|
||||
|
||||
func _on_global_cooldown_updated(time_left: float, max_time: float):
|
||||
for effect in icon_containers:
|
||||
var btn = icon_containers[effect]
|
||||
var overlay = btn.get_node_or_null("CooldownOverlay")
|
||||
if overlay:
|
||||
if time_left > 0:
|
||||
overlay.visible = true
|
||||
overlay.anchor_top = 1.0 - (time_left / max_time)
|
||||
btn.disabled = true
|
||||
else:
|
||||
overlay.visible = false
|
||||
overlay.anchor_top = 1.0
|
||||
if special_manager_ref and special_manager_ref.inventory.get(effect, false):
|
||||
btn.disabled = false
|
||||
if not power_up_button: return
|
||||
|
||||
var overlay = power_up_button.get_node_or_null("CooldownOverlay")
|
||||
if overlay:
|
||||
if time_left > 0:
|
||||
overlay.visible = true
|
||||
overlay.anchor_top = 1.0 - (time_left / max_time)
|
||||
power_up_button.disabled = true
|
||||
else:
|
||||
overlay.visible = false
|
||||
overlay.anchor_top = 1.0
|
||||
if current_effect != -1:
|
||||
power_up_button.disabled = false
|
||||
|
||||
func _connect_special_manager(special_manager):
|
||||
special_manager_ref = special_manager
|
||||
print("[PowerUpUI] Connected to SpecialTilesManager")
|
||||
|
||||
# Connect signals if not already connected
|
||||
if not special_manager.is_connected("powerup_unlocked", _on_powerup_unlocked):
|
||||
special_manager.connect("powerup_unlocked", _on_powerup_unlocked)
|
||||
|
||||
if not special_manager.is_connected("inventory_updated", _on_inventory_updated):
|
||||
special_manager.connect("inventory_updated", _on_inventory_updated)
|
||||
|
||||
@@ -189,56 +161,36 @@ func _connect_special_manager(special_manager):
|
||||
special_manager.connect("global_cooldown_updated", _on_global_cooldown_updated)
|
||||
|
||||
# Initial State Sync
|
||||
if icon_containers.is_empty():
|
||||
print("[PowerUpUI] Warning: Icon containers empty during setup. Attempting _ready logic now...")
|
||||
var container = get_node_or_null("Container")
|
||||
if container:
|
||||
_setup_btn(0, container.get_node_or_null("SpeedBtn"))
|
||||
_setup_btn(1, container.get_node_or_null("FreezeAreaBtn"))
|
||||
_setup_btn(2, container.get_node_or_null("WallBtn"))
|
||||
_setup_btn(3, container.get_node_or_null("GhostBtn"))
|
||||
if not power_up_button:
|
||||
_ready()
|
||||
|
||||
# Sync Inventory
|
||||
_on_inventory_updated(special_manager.inventory)
|
||||
|
||||
# Sync Levels for owned items
|
||||
for effect in special_manager.inventory:
|
||||
if special_manager.inventory[effect]:
|
||||
var lvl = special_manager.powerup_levels.get(effect, 1)
|
||||
_on_powerup_unlocked(effect, lvl)
|
||||
|
||||
func _on_powerup_unlocked(effect: int, level: int):
|
||||
# Enable button and set level
|
||||
if icon_containers.has(effect):
|
||||
var btn = icon_containers[effect]
|
||||
print("[PowerUpUI] Enabling button for Effect %d (Node: %s)" % [effect, btn.name])
|
||||
btn.disabled = false
|
||||
btn.modulate = Color.WHITE # Restore color
|
||||
btn.visible = true # Ensure visible
|
||||
|
||||
|
||||
# Enforce 1-slot rule by hiding others
|
||||
if special_manager_ref:
|
||||
_on_inventory_updated(special_manager_ref.inventory)
|
||||
else:
|
||||
print("[PowerUpUI] ERROR: Unlocked Effect %d but no UI button found! Keys: %s" % [effect, icon_containers.keys()])
|
||||
|
||||
|
||||
func _on_inventory_updated(inventory: Dictionary):
|
||||
# Update UI icons (Only show ONE active slot as per user request)
|
||||
print("[PowerUpUI] Inventory Updated Signal Received! Data: ", inventory)
|
||||
for effect in icon_containers:
|
||||
var has_item = inventory.get(effect, false)
|
||||
var btn = icon_containers[effect]
|
||||
if not power_up_button: return
|
||||
|
||||
# Update UI icon (Single slot logic)
|
||||
var active_effect: int = -1
|
||||
for effect in inventory:
|
||||
if inventory[effect] == true:
|
||||
active_effect = effect
|
||||
break
|
||||
|
||||
current_effect = active_effect
|
||||
|
||||
if active_effect != -1:
|
||||
power_up_button.visible = true
|
||||
power_up_button.icon = effect_textures.get(active_effect)
|
||||
|
||||
# Single slot logic: Only the owned one is visible
|
||||
btn.visible = has_item
|
||||
if has_item:
|
||||
# Check global cooldown before enabling
|
||||
var is_cooling = false
|
||||
if special_manager_ref and special_manager_ref.global_cooldown_timer > 0:
|
||||
is_cooling = true
|
||||
|
||||
btn.disabled = is_cooling
|
||||
btn.modulate = Color.WHITE
|
||||
_update_btn_shortcut(effect, btn)
|
||||
# Check global cooldown
|
||||
var is_cooling = false
|
||||
if special_manager_ref and special_manager_ref.global_cooldown_timer > 0:
|
||||
is_cooling = true
|
||||
|
||||
power_up_button.disabled = is_cooling
|
||||
power_up_button.modulate = Color.WHITE
|
||||
_update_btn_shortcut(power_up_button)
|
||||
else:
|
||||
power_up_button.visible = false
|
||||
power_up_button.disabled = true
|
||||
|
||||
Reference in New Issue
Block a user