From 36485c7f259e21690f3c5fca33fb375833056ee8 Mon Sep 17 00:00:00 2001 From: Yogi Wiguna Date: Thu, 26 Feb 2026 10:02:39 +0800 Subject: [PATCH] feat: introduce StopNGoManager to handle game phases, mission objectives, and dynamic arena setup with synchronized HUD elements. --- scripts/managers/stop_n_go_manager.gd | 75 ++++++++++++++------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/scripts/managers/stop_n_go_manager.gd b/scripts/managers/stop_n_go_manager.gd index 5d15579..7efda86 100644 --- a/scripts/managers/stop_n_go_manager.gd +++ b/scripts/managers/stop_n_go_manager.gd @@ -11,7 +11,7 @@ enum Phase {GO, STOP} const GO_DURATION: float = 8.0 const STOP_DURATION: float = 4.0 -const REQUIRED_GOALS: int = 5 +const REQUIRED_GOALS: int = 8 var current_phase: Phase = Phase.GO var phase_timer: float = GO_DURATION @@ -28,7 +28,6 @@ const TILE_SAFE = 2 # Green Safe Zone const TILE_OBSTACLE = 4 # Wall var hud_layer: CanvasLayer -var phase_label: Label var mission_label: Label var red_tint_overlay: ColorRect @@ -45,6 +44,7 @@ func _ready(): func _setup_hud(): hud_layer = CanvasLayer.new() + hud_layer.layer = 5 # Ensure it's above normal UI but below Pause Menu (10) hud_layer.visible = false add_child(hud_layer) @@ -55,38 +55,24 @@ func _setup_hud(): red_tint_overlay.visible = false # Hidden initially hud_layer.add_child(red_tint_overlay) - var vbox = VBoxContainer.new() - vbox.set_anchors_preset(Control.PRESET_TOP_RIGHT) - vbox.offset_right = -20 - vbox.offset_top = 100 - hud_layer.add_child(vbox) + # New container for bottom-mid label + var bottom_container = CenterContainer.new() + bottom_container.set_anchors_preset(Control.PRESET_CENTER_BOTTOM) + bottom_container.grow_horizontal = Control.GROW_DIRECTION_BOTH + bottom_container.grow_vertical = Control.GROW_DIRECTION_BEGIN + bottom_container.offset_bottom = -50 + hud_layer.add_child(bottom_container) - # Style for HUD - var style = StyleBoxFlat.new() - style.bg_color = Color(0, 0, 0, 0.4) - style.content_margin_left = 10 - style.content_margin_top = 10 - style.content_margin_right = 10 - style.content_margin_bottom = 10 - - var panel = PanelContainer.new() - panel.add_theme_stylebox_override("panel", style) - vbox.add_child(panel) - - var inner_vbox = VBoxContainer.new() - panel.add_child(inner_vbox) - - phase_label = Label.new() - phase_label.text = "PHASE: GO" - phase_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT - phase_label.add_theme_font_size_override("font_size", 32) - phase_label.add_theme_color_override("font_color", Color.GREEN) - inner_vbox.add_child(phase_label) + var custom_font = load("res://assets/fonts/Nougat-ExtraBlack.ttf") mission_label = Label.new() - mission_label.text = "MISSION: Collect 3 Items" - mission_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT - inner_vbox.add_child(mission_label) + mission_label.text = "MISSION: Collect Goals" + mission_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + if custom_font: mission_label.add_theme_font_override("font", custom_font) + mission_label.add_theme_font_size_override("font_size", 28) # Slightly larger since it's centered + mission_label.add_theme_color_override("font_outline_color", Color.BLACK) + mission_label.add_theme_constant_override("outline_size", 8) + bottom_container.add_child(mission_label) func _process(delta): if not is_active: @@ -105,12 +91,13 @@ func _process(delta): # Update HUD locally _update_hud_visuals() +func _on_goal_count_updated(_peer_id: int, _count: int): + # Refresh visuals whenever points change + _update_hud_visuals() + +var _has_notified_mission_complete: bool = false + func _update_hud_visuals(): - var phase_name = "GO" if current_phase == Phase.GO else "STOP" - if phase_label: - phase_label.text = "PHASE: %s (%.0fs)" % [phase_name, max(0, phase_timer)] - phase_label.add_theme_color_override("font_color", Color.GREEN if current_phase == Phase.GO else Color.RED) - # Toggle Red Screen Tint if red_tint_overlay: red_tint_overlay.visible = (current_phase == Phase.STOP) @@ -128,8 +115,16 @@ func _update_hud_visuals(): if completed_count >= REQUIRED_GOALS: mission_label.text = "ALL GOALS COMPLETE!\nREACH THE FINISH!" mission_label.add_theme_color_override("font_color", Color.GOLD) + + # Notify player once + if my_id == multiplayer.get_unique_id() and not _has_notified_mission_complete: + _has_notified_mission_complete = true + var player_node = main.get_node_or_null(str(my_id)) + if player_node: + NotificationManager.send_message(player_node, "ALL GOALS COMPLETE!", NotificationManager.MessageType.GOAL) else: mission_label.add_theme_color_override("font_color", Color.WHITE) + _has_notified_mission_complete = false # Update StopTimer (Traffic Light) _update_stop_timer_visuals() @@ -190,6 +185,14 @@ func activate_client_side(): is_active = true if hud_layer: hud_layer.visible = true + + # Connect to GoalsCycleManager for immediate HUD updates + var main = get_node_or_null("/root/Main") + if main: + var gcm = main.get_node_or_null("GoalsCycleManager") + if gcm and not gcm.goal_count_updated.is_connected(_on_goal_count_updated): + gcm.goal_count_updated.connect(_on_goal_count_updated) + set_process(true) func start_game_mode():