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
+21 -4
View File
@@ -7,6 +7,11 @@ extends GameMode
signal timer_updated(minutes: int, seconds: int)
signal score_changed(score: Dictionary)
# winning_team is -1 for a draw.
signal match_ended(winning_team: int, score: Dictionary)
# How long the result overlay stays up before returning to the menu.
const RESULT_SCREEN_SECONDS := 5.0
@export var match_length_seconds := 150.0
@@ -36,14 +41,17 @@ func _start() -> void:
func _make_opponent_controller() -> ShipController:
if not bot_model_path.is_empty() and FileAccess.file_exists(bot_model_path):
# The main menu's dropdown selection (GameSettings autoload) wins over the
# scene's export, which stays as the fallback for direct-scene runs.
var path := bot_model_path if GameSettings.selected_bot_path.is_empty() else GameSettings.selected_bot_path
if not path.is_empty() and FileAccess.file_exists(path):
var bot := AIShipController.new()
bot.model_path = bot_model_path
bot.model_path = path
bot.reaction_ticks = bot_reaction_ticks
bot.action_noise = bot_action_noise
return bot
if not bot_model_path.is_empty():
push_warning("MatchMode: bot model not found at %s, spawning inert opponent" % bot_model_path)
if not path.is_empty():
push_warning("MatchMode: bot model not found at %s, spawning inert opponent" % path)
return ShipController.new() # inert placeholder
@@ -64,4 +72,13 @@ func _on_goal_scored(conceding_team: int) -> void:
func _on_match_timer_timeout() -> void:
print("Full time! Final score: %d - %d" % [score[0], score[1]])
var winning_team := -1
if score[0] != score[1]:
winning_team = 0 if score[0] > score[1] else 1
match_ended.emit(winning_team, score.duplicate())
# Freeze gameplay while the HUD (process_mode ALWAYS) shows the result.
get_tree().paused = true
await get_tree().create_timer(RESULT_SCREEN_SECONDS).timeout
# Unpause before leaving, or the menu arrives paused and unresponsive.
get_tree().paused = false
get_tree().change_scene_to_file(MAIN_MENU_SCENE_PATH)