From aa6d6dcec2c2297c2872645a052bf54756cb1c81 Mon Sep 17 00:00:00 2001 From: Yogi Wiguna Date: Tue, 24 Feb 2026 11:35:45 +0800 Subject: [PATCH] feat: Initialize core game scene, managers, UI, multiplayer spawning, message bar, and pre-game countdown. --- scenes/main.gd | 66 +++++++++++++++++++------- scripts/bot_controller.gd | 4 ++ scripts/managers/game_state_manager.gd | 2 +- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/scenes/main.gd b/scenes/main.gd index be54587..1725614 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -246,6 +246,47 @@ func add_message_to_bar(player_name: String, message: String, type: int = Messag func broadcast_message(player_name: String, message: String): add_message_to_bar(player_name, message) +func _start_pre_game_countdown(): + """Show a 3-second countdown on all clients before starting.""" + for i in range(3, 0, -1): + if can_rpc(): + rpc("sync_countdown", str(i)) + await get_tree().create_timer(1.0).timeout + + if can_rpc(): + rpc("sync_countdown", "GO!") + await get_tree().create_timer(0.5).timeout + + if can_rpc(): + rpc("sync_countdown", "") + +@rpc("call_local", "reliable") +func sync_countdown(text: String): + var label = get_node_or_null("CountdownLabel") + if not label and text != "": + label = Label.new() + label.name = "CountdownLabel" + add_child(label) + + # Center and Style + label.anchors_preset = Control.PRESET_CENTER + label.set_anchors_and_offsets_preset(Control.PRESET_CENTER) + label.grow_horizontal = Control.GROW_DIRECTION_BOTH + label.grow_vertical = Control.GROW_DIRECTION_BOTH + label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER + + label.add_theme_font_size_override("font_size", 120) + label.add_theme_color_override("font_outline_color", Color.BLACK) + label.add_theme_constant_override("outline_size", 12) + label.add_theme_color_override("font_color", Color.YELLOW) + + if label: + label.text = text + if text == "": + label.queue_free() + elif text == "GO!": + label.add_theme_color_override("font_color", Color.GREEN) func _setup_global_match_timer_ui(): """Create the global match timer display at the top of the screen.""" @@ -549,6 +590,9 @@ func _start_game(): # This safely sends RPCs over the completed socket connection _assign_random_spawn_positions() + # PRE-GAME COUNTDOWN (3s) + await _start_pre_game_countdown() + GameStateManager.start_game() if can_rpc(): rpc("sync_game_start", GameStateManager.players, TurnManager.turn_based_mode) @@ -695,26 +739,14 @@ func _assign_random_spawn_positions(): func _assign_stop_n_go_spawn_positions(all_players: Array): """Assigns spawns to the far left columns (Start Line) for Stop N Go mode.""" - var enhanced_gridmap = $EnhancedGridMap - var valid_spawns = [] - - # Find all walkable tiles in the ONLY first column (x = 0) - for x in range(1): - for z in range(enhanced_gridmap.rows): - var ground = enhanced_gridmap.get_cell_item(Vector3i(x, 0, z)) - if ground == 0 or ground == 2 or ground == 6: # Walkable, Start Line, or Safe Zone - valid_spawns.append(Vector2i(x, z)) - - valid_spawns.shuffle() - - # Sort players for deterministic assignment + # Sort players for deterministic assignment based on ID all_players.sort_custom(func(a, b): return a.name.to_int() < b.name.to_int()) var spawn_index = 0 for player in all_players: - var assigned_pos = Vector2i(0, 0) # Fallback - if spawn_index < valid_spawns.size(): - assigned_pos = valid_spawns[spawn_index] + # Use deterministic assignment from (0, 1) to (0, 8) to keep players separate + # Start Line is Column 0. We use rows 1 to 8. + var assigned_pos = Vector2i(0, spawn_index + 1) # Ensure immediate sync player.position = player.grid_to_world(assigned_pos) @@ -725,7 +757,7 @@ func _assign_stop_n_go_spawn_positions(all_players: Array): player.rpc("set_spawn_position", assigned_pos) spawn_index += 1 - print("[StopNGo] Assigned starting block %s to player %s" % [assigned_pos, player.name]) + print("[StopNGo] Assigned fixed starting block %s to player %s" % [assigned_pos, player.name]) # ============================================================================= # Tekton NPC Management diff --git a/scripts/bot_controller.gd b/scripts/bot_controller.gd index 4a1a827..e55a397 100644 --- a/scripts/bot_controller.gd +++ b/scripts/bot_controller.gd @@ -83,6 +83,10 @@ func _physics_process(delta): if not multiplayer.is_server(): return + # Only run if game has started + if not GameStateManager.is_game_started(): + return + # STUCK PREVENTION if actor.is_player_moving: _stuck_timer += delta diff --git a/scripts/managers/game_state_manager.gd b/scripts/managers/game_state_manager.gd index dcdf9ac..8b43449 100644 --- a/scripts/managers/game_state_manager.gd +++ b/scripts/managers/game_state_manager.gd @@ -5,7 +5,7 @@ extends Node signal game_started() signal game_state_changed() -@export var enable_bots: bool = false +@export var enable_bots: bool = true @export var max_players: int = 8 var players: Array = []