feat: Introduce lobby functionality with UI, server selection, and game state management.

This commit is contained in:
Yogi Wiguna
2026-02-06 13:48:18 +08:00
parent fb0d27ce43
commit 10aa309148
4 changed files with 352 additions and 68 deletions
+64 -46
View File
@@ -1234,12 +1234,21 @@ func _show_game_over_panel():
player_scores.sort_custom(func(a, b): return a.score > b.score)
# Display each player
for i in range(min(player_scores.size(), 4)):
for i in range(min(player_scores.size(), 8)):
var entry = HBoxContainer.new()
entry.add_theme_constant_override("separation", 20)
var rank_colors = [Color(1.0, 0.84, 0.0), Color(0.75, 0.75, 0.75), Color(0.8, 0.5, 0.2), Color(0.5, 0.5, 0.5)]
var rank_emojis = ["🥇", "🥈", "🥉", "4th"]
var rank_colors = [
Color(1.0, 0.84, 0.0), # Gold
Color(0.75, 0.75, 0.75), # Silver
Color(0.8, 0.5, 0.2), # Bronze
Color(0.5, 0.5, 0.5), # 4th
Color(0.5, 0.5, 0.5), # 5th
Color(0.5, 0.5, 0.5), # 6th
Color(0.5, 0.5, 0.5), # 7th
Color(0.5, 0.5, 0.5) # 8th
]
var rank_emojis = ["🥇", "🥈", "🥉", "4th", "5th", "6th", "7th", "8th"]
var rank_label = Label.new()
rank_label.text = rank_emojis[i]
@@ -1349,33 +1358,7 @@ func sync_leaderboard_data(player_data: Array):
player_data.sort_custom(func(a, b): return a.score > b.score)
# Update entries
for i in range(4):
var entry = vbox.get_node_or_null("Entry" + str(i + 1))
if not entry:
continue
if i < player_data.size():
var data = player_data[i]
var rank_label = entry.get_node_or_null("RankLabel")
var name_label = entry.get_node_or_null("NameLabel")
var score_label = entry.get_node_or_null("ScoreLabel")
if rank_label:
rank_label.text = _get_ordinal(i + 1)
if name_label:
name_label.text = str(data.name)
if score_label:
score_label.text = str(data.score)
entry.visible = true
# Highlight check
if data.peer_id == multiplayer.get_unique_id():
entry.modulate = Color(1.0, 1.0, 0.0) # Yellow
else:
entry.modulate = Color.WHITE
else:
entry.visible = false
_render_leaderboard_entries(player_data)
func _update_leaderboard_display():
var leaderboard_panel = get_node_or_null("LeaderboardPanel")
@@ -1402,30 +1385,66 @@ func _update_leaderboard_display():
# Sort by score descending
player_data.sort_custom(func(a, b): return a.score > b.score)
# Update entries
for i in range(4): # Max 4 entries
var entry = vbox.get_node_or_null("Entry" + str(i + 1))
if not entry:
continue
_render_leaderboard_entries(player_data)
func _render_leaderboard_entries(sorted_player_data: Array):
var leaderboard_panel = get_node_or_null("LeaderboardPanel")
if not leaderboard_panel: return
var vbox = leaderboard_panel.get_node_or_null("MarginContainer/VBox")
if not vbox: vbox = leaderboard_panel.get_node_or_null("VBox")
if not vbox: return
var my_id = multiplayer.get_unique_id()
var my_index = -1
for i in range(sorted_player_data.size()):
if sorted_player_data[i].peer_id == my_id:
my_index = i
break
# Determine items to display (Max 4 slots for HUD)
var items_to_display = []
# add top 3
for i in range(min(3, sorted_player_data.size())):
items_to_display.append({"data": sorted_player_data[i], "rank": i + 1})
if i < player_data.size():
var data = player_data[i]
# add 4th slot (Smart Slot)
if sorted_player_data.size() >= 4:
# If local player is outside top 3 (index > 2), show them in 4th slot
# But if they are exactly 4th (index 3), it's the same as showing 4th place.
# If they are 5th (index 4) or worse, we replace 4th place with them.
if my_index > 3:
# Show local player
items_to_display.append({"data": sorted_player_data[my_index], "rank": my_index + 1})
else:
# Show standard 4th place
items_to_display.append({"data": sorted_player_data[3], "rank": 4})
# Render
# We assume the HUD has 4 slots max, but code iterates up to 8 just in case UI has more and we want to hide them.
for i in range(8):
var entry = vbox.get_node_or_null("Entry" + str(i + 1))
if not entry: continue
# Only show up to 4 entries in this new "Smart" mode
if i < items_to_display.size() and i < 4:
var item = items_to_display[i]
var data = item.data
var rank = item.rank
var rank_label = entry.get_node_or_null("RankLabel")
var name_label = entry.get_node_or_null("NameLabel")
var score_label = entry.get_node_or_null("ScoreLabel")
if rank_label:
rank_label.text = _get_ordinal(i + 1)
if name_label:
name_label.text = str(data.name)
if score_label:
score_label.text = str(data.score)
if rank_label: rank_label.text = _get_ordinal(rank)
if name_label: name_label.text = str(data.name)
if score_label: score_label.text = str(data.score)
entry.visible = true
# Highlight check
if data.peer_id == multiplayer.get_unique_id():
if data.peer_id == my_id:
entry.modulate = Color(1.0, 1.0, 0.0) # Yellow
else:
entry.modulate = Color.WHITE
@@ -1437,7 +1456,6 @@ func _get_ordinal(n: int) -> String:
1: return "1st"
2: return "2nd"
3: return "3rd"
4: return "4th"
_: return str(n) + "th"
# =============================================================================