feat(*): Add bot selection, score HUD, and winner reveal to matches, replace HUD text with aircraft-style flight instruments, and fix camera judder

This commit is contained in:
Josh Creek
2026-07-20 07:12:09 +01:00
parent 48369c50dc
commit 240e362f2f
20 changed files with 653 additions and 91 deletions
+133 -33
View File
@@ -1,11 +1,15 @@
[gd_scene load_steps=3 format=3 uid="uid://c8kak2l3m4n5"]
[gd_scene load_steps=6 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"]
[ext_resource type="Script" path="res://scripts/hud_heading_tape.gd" id="3_tape"]
[ext_resource type="Script" path="res://scripts/hud_gauge.gd" id="4_gauge"]
[sub_resource type="LabelSettings" id="LabelSettings_hud"]
font_size = 32
[node name="HUD" type="CanvasLayer"]
process_mode = 3
script = ExtResource("1_hud_controller")
[node name="Control" type="Control" parent="."]
@@ -15,6 +19,7 @@ anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
[node name="TimerLabel" type="Label" parent="Control"]
layout_mode = 1
@@ -28,7 +33,37 @@ grow_horizontal = 2
label_settings = SubResource("LabelSettings_hud")
horizontal_alignment = 1
[node name="Instruments" type="Control" parent="Control"]
[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"]
layout_mode = 2
theme_override_colors/font_color = Color(1, 0.5, 0.15, 1)
theme_override_font_sizes/font_size = 32
text = "0"
[node name="ResultOverlay" type="Control" parent="Control"]
visible = false
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
@@ -36,48 +71,113 @@ anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="InfoPanel" type="VBoxContainer" parent="Control"]
[node name="Dim" type="ColorRect" parent="Control/ResultOverlay"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0, 0, 0, 0.5)
[node name="Center" type="CenterContainer" parent="Control/ResultOverlay"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="VBox" type="VBoxContainer" parent="Control/ResultOverlay/Center"]
layout_mode = 2
theme_override_constants/separation = 16
[node name="ResultLabel" type="Label" parent="Control/ResultOverlay/Center/VBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 56
text = "Draw"
horizontal_alignment = 1
[node name="FinalScoreLabel" type="Label" parent="Control/ResultOverlay/Center/VBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 36
text = "0 - 0"
horizontal_alignment = 1
[node name="Instruments" type="Control" parent="Control"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
[node name="HeadingTape" type="Control" parent="Control/Instruments"]
layout_mode = 1
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -180.0
offset_right = 180.0
offset_top = 116.0
offset_bottom = 156.0
grow_horizontal = 2
mouse_filter = 2
script = ExtResource("3_tape")
[node name="Cluster" type="VBoxContainer" parent="Control/Instruments"]
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_left = 10.0
offset_top = -200.0
offset_right = 300.0
offset_bottom = -10.0
offset_left = 16.0
offset_top = -248.0
offset_right = 294.0
offset_bottom = -16.0
grow_vertical = 0
theme_override_constants/separation = 8
mouse_filter = 2
[node name="SpeedLabel" type="Label" parent="Control/InfoPanel"]
[node name="Dials" type="HBoxContainer" parent="Control/Instruments/Cluster"]
layout_mode = 2
text = "Speed: 0.0 m/s"
label_settings = SubResource("LabelSettings_hud")
theme_override_constants/separation = 8
mouse_filter = 2
[node name="AltitudeLabel" type="Label" parent="Control/InfoPanel"]
[node name="SpeedGauge" type="Control" parent="Control/Instruments/Cluster/Dials"]
custom_minimum_size = Vector2(46, 170)
layout_mode = 2
text = "Altitude: 0.0 m"
label_settings = SubResource("LabelSettings_hud")
mouse_filter = 2
script = ExtResource("4_gauge")
label = "SPD"
max_value = 35.0
[node name="AngularVelLabel" type="Label" parent="Control/InfoPanel"]
[node name="AttitudeIndicator" type="Control" parent="Control/Instruments/Cluster/Dials"]
custom_minimum_size = Vector2(170, 170)
layout_mode = 2
text = "Angular Vel: 0.0 rad/s"
label_settings = SubResource("LabelSettings_hud")
mouse_filter = 2
script = ExtResource("2_adi")
[node name="CameraModeLabel" type="Label" parent="Control/InfoPanel"]
[node name="AltitudeGauge" type="Control" parent="Control/Instruments/Cluster/Dials"]
custom_minimum_size = Vector2(46, 170)
layout_mode = 2
mouse_filter = 2
script = ExtResource("4_gauge")
label = "ALT"
max_value = 12.0
value_format = "%.1f"
[node name="ThrustBar" type="Control" parent="Control/Instruments/Cluster"]
custom_minimum_size = Vector2(278, 16)
layout_mode = 2
mouse_filter = 2
script = ExtResource("4_gauge")
label = "THR"
horizontal = true
fill_color = Color(1, 0.55, 0.15, 0.85)
[node name="CameraModeLabel" type="Label" parent="Control/Instruments/Cluster"]
modulate = Color(1, 1, 1, 0.6)
layout_mode = 2
theme_override_font_sizes/font_size = 14
text = "Camera: Ball Cam"
label_settings = SubResource("LabelSettings_hud")
[node name="AttitudeLabel" type="Label" parent="Control/InfoPanel"]
layout_mode = 2
text = "Pitch: 0° Roll: 0°"
label_settings = SubResource("LabelSettings_hud")
[node name="HeadingLabel" type="Label" parent="Control/InfoPanel"]
layout_mode = 2
text = "Heading: 0°"
label_settings = SubResource("LabelSettings_hud")
[node name="ThrustLabel" type="Label" parent="Control/InfoPanel"]
layout_mode = 2
text = "Thrust: 0%"
label_settings = SubResource("LabelSettings_hud")
+88 -7
View File
@@ -20,8 +20,9 @@ grow_horizontal = 2
grow_vertical = 2
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
custom_minimum_size = Vector2(420, 0)
layout_mode = 2
theme_override_constants/separation = 24
theme_override_constants/separation = 10
[node name="TitleLabel" type="Label" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
@@ -29,20 +30,100 @@ theme_override_font_sizes/font_size = 48
text = "Cosmic Clash"
horizontal_alignment = 1
[node name="SubtitleLabel" type="Label" parent="CenterContainer/VBoxContainer"]
modulate = Color(1, 1, 1, 0.55)
layout_mode = 2
theme_override_font_sizes/font_size = 16
text = "Physics-based soccer in space"
horizontal_alignment = 1
[node name="TitleSpacer" type="Control" parent="CenterContainer/VBoxContainer"]
custom_minimum_size = Vector2(0, 14)
layout_mode = 2
[node name="FreePlayButton" type="Button" parent="CenterContainer/VBoxContainer"]
custom_minimum_size = Vector2(330, 60)
custom_minimum_size = Vector2(0, 56)
layout_mode = 2
text = "Free Play"
[node name="MatchButton" type="Button" parent="CenterContainer/VBoxContainer"]
custom_minimum_size = Vector2(330, 60)
[node name="FreePlayHint" type="Label" parent="CenterContainer/VBoxContainer"]
modulate = Color(1, 1, 1, 0.55)
layout_mode = 2
theme_override_font_sizes/font_size = 13
text = "Solo practice — no timer, R resets the ball"
horizontal_alignment = 1
[node name="MatchSeparator" type="HSeparator" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
[node name="MatchHeader" type="Label" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
theme_override_font_sizes/font_size = 22
text = "Match"
[node name="SpectateButton" type="Button" parent="CenterContainer/VBoxContainer"]
custom_minimum_size = Vector2(330, 60)
[node name="MatchHint" type="Label" parent="CenterContainer/VBoxContainer"]
modulate = Color(1, 1, 1, 0.55)
layout_mode = 2
text = "Spectate (Bot vs Bot)"
theme_override_font_sizes/font_size = 13
text = "A 2:30 match — you vs a trained bot"
[node name="MatchRow" type="HBoxContainer" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 10
[node name="OpponentLabel" type="Label" parent="CenterContainer/VBoxContainer/MatchRow"]
layout_mode = 2
text = "Opponent"
[node name="BotDropdown" type="OptionButton" parent="CenterContainer/VBoxContainer/MatchRow"]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 40)
layout_mode = 2
size_flags_horizontal = 3
[node name="MatchButton" type="Button" parent="CenterContainer/VBoxContainer"]
custom_minimum_size = Vector2(0, 56)
layout_mode = 2
text = "Play Match"
[node name="SpectateSeparator" type="HSeparator" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
[node name="SpectateHeader" type="Label" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
theme_override_font_sizes/font_size = 22
text = "Spectate"
[node name="SpectateHint" type="Label" parent="CenterContainer/VBoxContainer"]
modulate = Color(1, 1, 1, 0.55)
layout_mode = 2
theme_override_font_sizes/font_size = 13
text = "Watch two bots play each other"
[node name="SpectateRow" type="HBoxContainer" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 10
[node name="BotADropdown" type="OptionButton" parent="CenterContainer/VBoxContainer/SpectateRow"]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 40)
layout_mode = 2
size_flags_horizontal = 3
[node name="VsLabel" type="Label" parent="CenterContainer/VBoxContainer/SpectateRow"]
layout_mode = 2
text = "vs"
[node name="BotBDropdown" type="OptionButton" parent="CenterContainer/VBoxContainer/SpectateRow"]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 40)
layout_mode = 2
size_flags_horizontal = 3
[node name="SpectateButton" type="Button" parent="CenterContainer/VBoxContainer"]
custom_minimum_size = Vector2(0, 56)
layout_mode = 2
text = "Watch Match"
[connection signal="pressed" from="CenterContainer/VBoxContainer/FreePlayButton" to="." method="_on_free_play_pressed"]
[connection signal="pressed" from="CenterContainer/VBoxContainer/MatchButton" to="." method="_on_match_pressed"]
+1 -1
View File
@@ -6,7 +6,7 @@
[node name="Match" type="Node3D"]
script = ExtResource("1_m")
bot_model_path = "res://bots/run03.json"
bot_model_path = "res://bots/run05.json"
[node name="Arena" parent="." instance=ExtResource("2_m")]
+2 -2
View File
@@ -6,8 +6,8 @@
[node name="Spectate" type="Node3D"]
script = ExtResource("1_s")
bot_a_model_path = "res://bots/run02.json"
bot_b_model_path = "res://bots/run01.json"
bot_a_model_path = "res://bots/run05.json"
bot_b_model_path = "res://bots/run05.json"
[node name="Arena" parent="." instance=ExtResource("2_s")]