feat(*): Redesign HUD scoreboard as a single timer/score/team banner

This commit is contained in:
Josh Creek
2026-07-28 19:24:40 +01:00
parent 93f90ca6de
commit a9b7b450d5
2 changed files with 87 additions and 40 deletions
+56 -31
View File
@@ -1,4 +1,4 @@
[gd_scene load_steps=7 format=3 uid="uid://c8kak2l3m4n5"]
[gd_scene load_steps=8 format=3 uid="uid://c8kak2l3m4n5"]
[ext_resource type="Script" uid="uid://du7y176h5aaq4" path="res://scripts/HUDController.gd" id="1_hud_controller"]
[ext_resource type="Script" path="res://scripts/hud_attitude_indicator.gd" id="2_adi"]
@@ -11,6 +11,17 @@ font_size = 32
[sub_resource type="LabelSettings" id="LabelSettings_kickoff"]
font_size = 96
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_scoreboard"]
bg_color = Color(0.05, 0.06, 0.09, 0.6)
corner_radius_top_left = 10
corner_radius_top_right = 10
corner_radius_bottom_right = 10
corner_radius_bottom_left = 10
content_margin_left = 20.0
content_margin_top = 8.0
content_margin_right = 20.0
content_margin_bottom = 8.0
[node name="HUD" type="CanvasLayer"]
process_mode = 3
script = ExtResource("1_hud_controller")
@@ -24,47 +35,61 @@ grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
[node name="TimerLabel" type="Label" parent="Control"]
[node name="ScoreboardPanel" type="PanelContainer" parent="Control"]
layout_mode = 1
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -90.5
offset_right = 90.5
offset_bottom = 62.0
offset_left = -220.0
offset_right = 220.0
offset_top = 8.0
offset_bottom = 60.0
grow_horizontal = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_scoreboard")
[node name="ScoreRow" type="HBoxContainer" parent="Control/ScoreboardPanel"]
layout_mode = 2
alignment = 1
theme_override_constants/separation = 16
[node name="Team0Name" type="Label" parent="Control/ScoreboardPanel/ScoreRow"]
layout_mode = 2
size_flags_vertical = 4
theme_override_colors/font_color = Color(0.25, 0.55, 1, 1)
theme_override_font_sizes/font_size = 14
horizontal_alignment = 1
text = "BLUE"
[node name="Team0Score" type="Label" parent="Control/ScoreboardPanel/ScoreRow"]
layout_mode = 2
size_flags_vertical = 4
theme_override_colors/font_color = Color(0.25, 0.55, 1, 1)
theme_override_font_sizes/font_size = 32
horizontal_alignment = 1
text = "0"
[node name="TimerLabel" type="Label" parent="Control/ScoreboardPanel/ScoreRow"]
layout_mode = 2
size_flags_vertical = 4
label_settings = SubResource("LabelSettings_hud")
horizontal_alignment = 1
[node name="ScoreRow" type="HBoxContainer" parent="Control"]
layout_mode = 1
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -90.5
offset_right = 90.5
offset_top = 64.0
offset_bottom = 110.0
grow_horizontal = 2
alignment = 1
[node name="Team0Score" type="Label" parent="Control/ScoreRow"]
layout_mode = 2
theme_override_colors/font_color = Color(0.25, 0.55, 1, 1)
theme_override_font_sizes/font_size = 32
text = "0"
[node name="ScoreDash" type="Label" parent="Control/ScoreRow"]
layout_mode = 2
theme_override_font_sizes/font_size = 32
text = " - "
[node name="Team1Score" type="Label" parent="Control/ScoreRow"]
[node name="Team1Score" type="Label" parent="Control/ScoreboardPanel/ScoreRow"]
layout_mode = 2
size_flags_vertical = 4
theme_override_colors/font_color = Color(1, 0.5, 0.15, 1)
theme_override_font_sizes/font_size = 32
horizontal_alignment = 1
text = "0"
[node name="Team1Name" type="Label" parent="Control/ScoreboardPanel/ScoreRow"]
layout_mode = 2
size_flags_vertical = 4
theme_override_colors/font_color = Color(1, 0.5, 0.15, 1)
theme_override_font_sizes/font_size = 14
horizontal_alignment = 1
text = "ORANGE"
[node name="KickoffLabel" type="Label" parent="Control"]
visible = false
layout_mode = 1
@@ -141,8 +166,8 @@ anchor_left = 0.5
anchor_right = 0.5
offset_left = -180.0
offset_right = 180.0
offset_top = 116.0
offset_bottom = 156.0
offset_top = 68.0
offset_bottom = 108.0
grow_horizontal = 2
mouse_filter = 2
script = ExtResource("3_tape")
+31 -9
View File
@@ -5,10 +5,12 @@
extends CanvasLayer
class_name HUDController
@onready var timer_label = get_node("Control/TimerLabel")
@onready var score_row = get_node_or_null("Control/ScoreRow")
@onready var team0_score_label = get_node_or_null("Control/ScoreRow/Team0Score")
@onready var team1_score_label = get_node_or_null("Control/ScoreRow/Team1Score")
@onready var score_row = get_node_or_null("Control/ScoreboardPanel")
@onready var timer_label = get_node_or_null("Control/ScoreboardPanel/ScoreRow/TimerLabel")
@onready var team0_name_label = get_node_or_null("Control/ScoreboardPanel/ScoreRow/Team0Name")
@onready var team0_score_label = get_node_or_null("Control/ScoreboardPanel/ScoreRow/Team0Score")
@onready var team1_score_label = get_node_or_null("Control/ScoreboardPanel/ScoreRow/Team1Score")
@onready var team1_name_label = get_node_or_null("Control/ScoreboardPanel/ScoreRow/Team1Name")
@onready var kickoff_label = get_node_or_null("Control/KickoffLabel")
@onready var result_overlay = get_node_or_null("Control/ResultOverlay")
@onready var result_label = get_node_or_null("Control/ResultOverlay/Center/VBox/ResultLabel")
@@ -26,6 +28,7 @@ const TEAM_NAMES := {0: "Blue", 1: "Orange"}
const TEAM_COLORS := {0: Color(0.25, 0.55, 1.0), 1: Color(1.0, 0.5, 0.15)}
var ship: Node
var _last_score := {0: 0, 1: 0}
func _ready():
# Wait one frame to ensure ship is ready and added to group
@@ -67,8 +70,14 @@ func _initialize_hud():
var has_score = game_manager and game_manager.has_signal("score_changed")
if has_score:
game_manager.score_changed.connect(_on_score_changed)
for label in [team0_name_label, team0_score_label, team1_score_label, team1_name_label]:
if label and is_instance_valid(label):
label.visible = has_score
# The banner itself (timer + score share one panel) only fully hides
# when neither signal exists at all.
if score_row and is_instance_valid(score_row):
score_row.visible = has_score
score_row.visible = has_timer or has_score
if game_manager and game_manager.has_signal("match_ended"):
game_manager.match_ended.connect(_on_match_ended)
@@ -126,10 +135,23 @@ func update_timer(time_text: String):
timer_label.text = time_text
func _on_score_changed(score: Dictionary):
if team0_score_label and is_instance_valid(team0_score_label):
team0_score_label.text = str(score.get(0, 0))
if team1_score_label and is_instance_valid(team1_score_label):
team1_score_label.text = str(score.get(1, 0))
_update_score_label(team0_score_label, score, 0)
_update_score_label(team1_score_label, score, 1)
_last_score = score.duplicate()
func _update_score_label(label: Label, score: Dictionary, team: int):
if not label or not is_instance_valid(label):
return
label.text = str(score.get(team, 0))
if score.get(team, 0) > _last_score.get(team, 0):
_flash_score_label(label)
# Brief scale pop to draw the eye to whichever team just scored.
func _flash_score_label(label: Label) -> void:
label.pivot_offset = label.size / 2.0
var tween := create_tween()
tween.tween_property(label, "scale", Vector2(1.4, 1.4), 0.1)
tween.tween_property(label, "scale", Vector2(1.0, 1.0), 0.2)
func _on_kickoff_countdown(count: int):
if not kickoff_label or not is_instance_valid(kickoff_label):