feat: Implement UIManager for player action, playerboard, and power-up UI, and add initial lobby, main scenes, and PlayerboardManager.

This commit is contained in:
Yogi Wiguna
2026-02-09 11:35:45 +08:00
parent 1048d7e0ca
commit 20e9897481
4 changed files with 128 additions and 32 deletions
+25
View File
@@ -385,6 +385,31 @@ theme_override_colors/font_color = Color(0.647, 0.996, 0.224, 1)
theme_override_font_sizes/font_size = 11 theme_override_font_sizes/font_size = 11
text = "Timer ✓" text = "Timer ✓"
[node name="ScarcitySpacer" type="Control" parent="LobbyPanel/TopBar/SettingsSection" unique_id=1261899999]
custom_minimum_size = Vector2(15, 0)
layout_mode = 2
[node name="ScarcityOption" type="OptionButton" parent="LobbyPanel/TopBar/SettingsSection" unique_id=448679999]
custom_minimum_size = Vector2(90, 28)
layout_mode = 2
theme_override_fonts/font = ExtResource("5_pc087")
theme_override_font_sizes/font_size = 11
item_count = 3
selected = 0
popup/item_0/text = "Normal"
popup/item_0/id = 0
popup/item_1/text = "Scarce"
popup/item_1/id = 1
popup/item_2/text = "Abundant"
popup/item_2/id = 2
[node name="ScarcityLabel" type="Label" parent="LobbyPanel/TopBar/SettingsSection" unique_id=191739999]
visible = false
layout_mode = 2
theme_override_colors/font_color = Color(0.647, 0.996, 0.224, 1)
theme_override_font_sizes/font_size = 11
text = "Normal"
[node name="HostBanner" type="PanelContainer" parent="LobbyPanel" unique_id=1670701936] [node name="HostBanner" type="PanelContainer" parent="LobbyPanel" unique_id=1670701936]
layout_mode = 1 layout_mode = 1
anchors_preset = 5 anchors_preset = 5
+29 -21
View File
@@ -117,10 +117,10 @@ material = SubResource("ShaderMaterial_j8jky")
anchors_preset = 4 anchors_preset = 4
anchor_top = 0.5 anchor_top = 0.5
anchor_bottom = 0.5 anchor_bottom = 0.5
offset_left = 24.0 offset_left = 63.731766
offset_top = -246.79544 offset_top = -200.62561
offset_right = 259.46997 offset_right = 214.42894
offset_bottom = -18.622345 offset_bottom = -15.877472
grow_vertical = 2 grow_vertical = 2
rotation = -0.10297442 rotation = -0.10297442
theme_override_styles/panel = SubResource("StyleBoxFlat_playerboard") theme_override_styles/panel = SubResource("StyleBoxFlat_playerboard")
@@ -130,10 +130,10 @@ clip_contents = true
anchors_preset = 4 anchors_preset = 4
anchor_top = 0.5 anchor_top = 0.5
anchor_bottom = 0.5 anchor_bottom = 0.5
offset_left = 36.0 offset_left = 34.000004
offset_top = -239.79541 offset_top = -190.23553
offset_right = 252.0 offset_right = 250.0
offset_bottom = -23.79541 offset_bottom = 25.764465
grow_vertical = 2 grow_vertical = 2
rotation = -0.10297442 rotation = -0.10297442
scale = Vector2(1.08, 1.08) scale = Vector2(1.08, 1.08)
@@ -141,6 +141,7 @@ size_flags_horizontal = 3
columns = 5 columns = 5
[node name="Slot1" type="TextureRect" parent="PlayerboardUI" unique_id=1399081516] [node name="Slot1" type="TextureRect" parent="PlayerboardUI" unique_id=1399081516]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -281,6 +282,7 @@ grow_vertical = 2
texture = ExtResource("9_6gcb6") texture = ExtResource("9_6gcb6")
[node name="Slot5" type="TextureRect" parent="PlayerboardUI" unique_id=1644684927] [node name="Slot5" type="TextureRect" parent="PlayerboardUI" unique_id=1644684927]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -316,6 +318,7 @@ grow_vertical = 2
texture = ExtResource("9_6gcb6") texture = ExtResource("9_6gcb6")
[node name="Slot6" type="TextureRect" parent="PlayerboardUI" unique_id=481932710] [node name="Slot6" type="TextureRect" parent="PlayerboardUI" unique_id=481932710]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -456,6 +459,7 @@ grow_vertical = 2
texture = ExtResource("9_6gcb6") texture = ExtResource("9_6gcb6")
[node name="Slot10" type="TextureRect" parent="PlayerboardUI" unique_id=1184621406] [node name="Slot10" type="TextureRect" parent="PlayerboardUI" unique_id=1184621406]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -491,6 +495,7 @@ grow_vertical = 2
texture = ExtResource("9_6gcb6") texture = ExtResource("9_6gcb6")
[node name="Slot11" type="TextureRect" parent="PlayerboardUI" unique_id=1688573384] [node name="Slot11" type="TextureRect" parent="PlayerboardUI" unique_id=1688573384]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -631,6 +636,7 @@ grow_vertical = 2
texture = ExtResource("9_6gcb6") texture = ExtResource("9_6gcb6")
[node name="Slot15" type="TextureRect" parent="PlayerboardUI" unique_id=1663725669] [node name="Slot15" type="TextureRect" parent="PlayerboardUI" unique_id=1663725669]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -666,6 +672,7 @@ grow_vertical = 2
texture = ExtResource("9_6gcb6") texture = ExtResource("9_6gcb6")
[node name="Slot16" type="TextureRect" parent="PlayerboardUI" unique_id=628611489] [node name="Slot16" type="TextureRect" parent="PlayerboardUI" unique_id=628611489]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -806,6 +813,7 @@ grow_vertical = 2
texture = ExtResource("9_6gcb6") texture = ExtResource("9_6gcb6")
[node name="Slot20" type="TextureRect" parent="PlayerboardUI" unique_id=2086008463] [node name="Slot20" type="TextureRect" parent="PlayerboardUI" unique_id=2086008463]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -841,6 +849,7 @@ grow_vertical = 2
texture = ExtResource("9_6gcb6") texture = ExtResource("9_6gcb6")
[node name="Slot21" type="TextureRect" parent="PlayerboardUI" unique_id=1451444134] [node name="Slot21" type="TextureRect" parent="PlayerboardUI" unique_id=1451444134]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -876,6 +885,7 @@ grow_vertical = 2
texture = ExtResource("9_6gcb6") texture = ExtResource("9_6gcb6")
[node name="Slot22" type="TextureRect" parent="PlayerboardUI" unique_id=141949470] [node name="Slot22" type="TextureRect" parent="PlayerboardUI" unique_id=141949470]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -911,6 +921,7 @@ grow_vertical = 2
texture = ExtResource("9_6gcb6") texture = ExtResource("9_6gcb6")
[node name="Slot23" type="TextureRect" parent="PlayerboardUI" unique_id=1345458769] [node name="Slot23" type="TextureRect" parent="PlayerboardUI" unique_id=1345458769]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -946,6 +957,7 @@ grow_vertical = 2
texture = ExtResource("9_6gcb6") texture = ExtResource("9_6gcb6")
[node name="Slot24" type="TextureRect" parent="PlayerboardUI" unique_id=1840834103] [node name="Slot24" type="TextureRect" parent="PlayerboardUI" unique_id=1840834103]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -981,6 +993,7 @@ grow_vertical = 2
texture = ExtResource("9_6gcb6") texture = ExtResource("9_6gcb6")
[node name="Slot25" type="TextureRect" parent="PlayerboardUI" unique_id=1179195394] [node name="Slot25" type="TextureRect" parent="PlayerboardUI" unique_id=1179195394]
modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(36, 36) custom_minimum_size = Vector2(36, 36)
layout_mode = 2 layout_mode = 2
texture = ExtResource("6_2vy7d") texture = ExtResource("6_2vy7d")
@@ -1017,10 +1030,10 @@ texture = ExtResource("9_6gcb6")
[node name="PlayerboardPanel2" type="PanelContainer" parent="." unique_id=1458381676] [node name="PlayerboardPanel2" type="PanelContainer" parent="." unique_id=1458381676]
material = SubResource("ShaderMaterial_j8jky") material = SubResource("ShaderMaterial_j8jky")
offset_left = 23.999996 offset_left = 22.0
offset_top = 66.99999 offset_top = 116.559875
offset_right = 243.46997 offset_right = 241.46997
offset_bottom = 106.66015 offset_bottom = 156.22003
rotation = -0.10297442 rotation = -0.10297442
theme_override_styles/panel = SubResource("StyleBoxFlat_playerboard") theme_override_styles/panel = SubResource("StyleBoxFlat_playerboard")
@@ -1028,21 +1041,16 @@ theme_override_styles/panel = SubResource("StyleBoxFlat_playerboard")
anchors_preset = 4 anchors_preset = 4
anchor_top = 0.5 anchor_top = 0.5
anchor_bottom = 0.5 anchor_bottom = 0.5
offset_left = 33.0 offset_left = 31.000004
offset_top = -293.0 offset_top = -243.44012
offset_right = 73.0 offset_right = 71.0
offset_bottom = -257.0 offset_bottom = -207.44012
grow_vertical = 2 grow_vertical = 2
rotation = -0.10297442 rotation = -0.10297442
theme_override_fonts/font = ExtResource("13_j8jky") theme_override_fonts/font = ExtResource("13_j8jky")
theme_override_font_sizes/font_size = 32 theme_override_font_sizes/font_size = 32
text = "X0" text = "X0"
[node name="CanvasLayer" type="CanvasLayer" parent="." unique_id=2131054934]
offset = Vector2(15, 50)
scale = Vector2(1.11, 1.0303639)
transform = Transform2D(1.11, 0, 0.105, 1.025, 15, 50)
[node name="PowerUpBar" type="PanelContainer" parent="." unique_id=1775378146] [node name="PowerUpBar" type="PanelContainer" parent="." unique_id=1775378146]
anchors_preset = 4 anchors_preset = 4
anchor_top = 0.5 anchor_top = 0.5
+43 -6
View File
@@ -10,6 +10,12 @@ var selected_gridmap_position = Vector2i(-1, -1)
var selected_playerboard_slot = -1 var selected_playerboard_slot = -1
var targeted_playerboard_slot = -1 var targeted_playerboard_slot = -1
# 0-based indices corresponding to User's 1-based request: 1,5,6,10,11,15,16,20,21,22,23,24,25
const HIDDEN_SLOTS = [0, 4, 5, 9, 10, 14, 15, 19, 20, 21, 22, 23, 24]
func is_valid_playerboard_slot(slot_index: int) -> bool:
return not (slot_index in HIDDEN_SLOTS)
func initialize(p_player: Node3D, p_gridmap: Node): func initialize(p_player: Node3D, p_gridmap: Node):
player = p_player player = p_player
enhanced_gridmap = p_gridmap enhanced_gridmap = p_gridmap
@@ -253,7 +259,13 @@ func bot_try_grab_item() -> bool:
var item = enhanced_gridmap.get_cell_item(current_cell) var item = enhanced_gridmap.get_cell_item(current_cell)
if item != -1: if item != -1:
var empty_slot = player.playerboard.find(-1) # Find empty slot that is NOT hidden
var empty_slot = -1
for i in range(player.playerboard.size()):
if player.playerboard[i] == -1 and not (i in HIDDEN_SLOTS):
empty_slot = i
break
if empty_slot != -1: if empty_slot != -1:
if player.is_multiplayer_authority(): if player.is_multiplayer_authority():
# Convert Holo (11-14) # Convert Holo (11-14)
@@ -281,7 +293,13 @@ func bot_try_grab_item() -> bool:
var cell = Vector3i(neighbor.position.x, 1, neighbor.position.y) var cell = Vector3i(neighbor.position.x, 1, neighbor.position.y)
item = enhanced_gridmap.get_cell_item(cell) item = enhanced_gridmap.get_cell_item(cell)
if item != -1: if item != -1:
var empty_slot = player.playerboard.find(-1) # Find empty slot that is NOT hidden
var empty_slot = -1
for i in range(player.playerboard.size()):
if player.playerboard[i] == -1 and not (i in HIDDEN_SLOTS):
empty_slot = i
break
if empty_slot != -1: if empty_slot != -1:
if player.is_multiplayer_authority(): if player.is_multiplayer_authority():
player.playerboard[empty_slot] = item player.playerboard[empty_slot] = item
@@ -477,7 +495,7 @@ func handle_slot_clicked(slot_index: int):
return return
var adjacent_slots = get_adjacent_playerboard_slots(selected_playerboard_slot) var adjacent_slots = get_adjacent_playerboard_slots(selected_playerboard_slot)
if slot_index in adjacent_slots and player.playerboard[slot_index] == -1: if slot_index in adjacent_slots and player.playerboard[slot_index] == -1 and not (slot_index in HIDDEN_SLOTS):
# Move item to empty target slot # Move item to empty target slot
var selected_item = player.playerboard[selected_playerboard_slot] var selected_item = player.playerboard[selected_playerboard_slot]
player.playerboard[slot_index] = selected_item player.playerboard[slot_index] = selected_item
@@ -526,11 +544,26 @@ func find_best_goal_slot_for_item(item: int) -> int:
var board_row = i + 1 # offset to center in 5x5 var board_row = i + 1 # offset to center in 5x5
var board_col = j + 1 var board_col = j + 1
var slot_index = board_row * 5 + board_col var slot_index = board_row * 5 + board_col
# Ensure this slot is not hidden (though 3x3 center should be safe, best to check)
if slot_index in HIDDEN_SLOTS:
continue
if player.playerboard[slot_index] == -1: # only if empty if player.playerboard[slot_index] == -1: # only if empty
return slot_index return slot_index
# No ideal slot? Return any empty slot # No ideal goal slot? Look for any empty slot that is NOT hidden AND NOT reserved for Goals
return player.playerboard.find(-1) # Goal slots are row 2-3, col 1-3 (indices: 11,12,13, 16,17,18) matching User request
# Rows 1 (6,7,8) are now storage slots
var reserved_goal_slots = [11, 12, 13, 16, 17, 18]
for i in range(player.playerboard.size()):
if player.playerboard[i] == -1:
if i in HIDDEN_SLOTS: continue
if i in reserved_goal_slots: continue # Skip if it's a goal slot (reserved)
return i
return -1
func find_best_put_candidate() -> Dictionary: func find_best_put_candidate() -> Dictionary:
# Convert goals to 2D (3x3) # Convert goals to 2D (3x3)
@@ -651,7 +684,11 @@ func has_items_in_playerboard() -> bool:
return player.playerboard.any(func(item): return item != -1) return player.playerboard.any(func(item): return item != -1)
func playerboard_is_full() -> bool: func playerboard_is_full() -> bool:
return player.playerboard.find(-1) == -1 # Check if any NON-HIDDEN slot is empty
for i in range(player.playerboard.size()):
if not (i in HIDDEN_SLOTS) and player.playerboard[i] == -1:
return false
return true
# Slot selection management # Slot selection management
func select_playerboard_slot(slot_index: int): func select_playerboard_slot(slot_index: int):
+31 -5
View File
@@ -101,8 +101,20 @@ func setup_playerboard_ui():
var adjacent_rect = TextureRect.new() var adjacent_rect = TextureRect.new()
var ar_tex = load("res://assets/models/pboard/AdjacentRect.tres") var ar_tex = load("res://assets/models/pboard/AdjacentRect.tres")
slot.custom_minimum_size = Vector2(36, 36) slot.custom_minimum_size = Vector2(36, 36)
slot.texture = item_tex[0] slot.texture = item_tex[0]
# 0-based indices corresponding to User's 1-based request: 1,5,6,10,11,15,16,20,21,22,23,24,25
var hidden_slots = [0, 4, 5, 9, 10, 14, 15, 19, 20, 21, 22, 23, 24]
if i in hidden_slots:
slot.modulate = Color(1, 1, 1, 0)
slot.mouse_filter = Control.MOUSE_FILTER_IGNORE
else:
slot.modulate = Color.WHITE
slot.mouse_filter = Control.MOUSE_FILTER_PASS
playerboard_ui.add_child(slot, true) playerboard_ui.add_child(slot, true)
highlight_rect.texture = hr_tex highlight_rect.texture = hr_tex
@@ -127,7 +139,10 @@ func update_playerboard_ui():
# Center 3x3 slot indices in a 5x5 grid (0-indexed) # Center 3x3 slot indices in a 5x5 grid (0-indexed)
# Row 1: 6, 7, 8 # Row 1: 6, 7, 8
# Row 2: 11, 12, 13 # Row 2: 11, 12, 13
# Row 3: 16, 17, 18 # Center 3x3 slot indices in a 5x5 grid (0-indexed)
# Row 1: 6, 7, 8 (Now Storage - but kept in index map for goals[0-2])
# Row 2: 11, 12, 13 (Goals[3-5])
# Row 3: 16, 17, 18 (Goals[6-8])
var center_slots = [6, 7, 8, 11, 12, 13, 16, 17, 18] var center_slots = [6, 7, 8, 11, 12, 13, 16, 17, 18]
var goals = local_player_character.goals if local_player_character.goals else [] var goals = local_player_character.goals if local_player_character.goals else []
@@ -140,13 +155,23 @@ func update_playerboard_ui():
var item = local_player_character.playerboard[i] var item = local_player_character.playerboard[i]
# 0-based indices corresponding to User's 1-based request: 1,5,6,10,11,15,16,20,21,22,23,24,25
var hidden_slots = [0, 4, 5, 9, 10, 14, 15, 19, 20, 21, 22, 23, 24]
# Default texture (empty) # Default texture (empty)
slot.texture = item_tex[0] slot.texture = item_tex[0]
slot.modulate = Color.WHITE
if i in hidden_slots:
slot.modulate = Color(1, 1, 1, 0)
slot.mouse_filter = Control.MOUSE_FILTER_IGNORE
else:
slot.modulate = Color.WHITE
slot.mouse_filter = Control.MOUSE_FILTER_PASS
# Check if this is a center slot that should show a goal # Check if this is a center slot that should show a goal
# BUT only show ghost goals for rows 2 & 3 (indices 11+)
var center_index = center_slots.find(i) var center_index = center_slots.find(i)
if center_index != -1 and center_index < goals.size(): if center_index != -1 and center_index < goals.size() and i > 8:
var goal_value = goals[center_index] var goal_value = goals[center_index]
if item != -1: if item != -1:
@@ -174,8 +199,9 @@ func update_playerboard_ui():
8: slot.texture = item_tex[2] 8: slot.texture = item_tex[2]
9: slot.texture = item_tex[3] 9: slot.texture = item_tex[3]
10: slot.texture = item_tex[4] 10: slot.texture = item_tex[4]
# Non-center slots always full brightness # Non-center slots always full brightness (UNLESS HIDDEN)
slot.modulate = Color.WHITE if not (i in hidden_slots):
slot.modulate = Color.WHITE
# Check for new special tile placement to trigger effect # Check for new special tile placement to trigger effect
if i < _previous_playerboard_state.size(): if i < _previous_playerboard_state.size():