From 9ae32ca6a9dc42d9f63ff5214741812ad61945a1 Mon Sep 17 00:00:00 2001 From: Olof Pettersson Date: Wed, 19 Nov 2025 18:45:42 +0100 Subject: [PATCH] Menu system WIP --- src/main.tscn | 7 +- src/scenes/UI/ingame_menu/ingame_menu.gd | 35 +++++++++ src/scenes/UI/ingame_menu/ingame_menu.gd.uid | 1 + src/scenes/UI/ingame_menu/ingame_menu.tscn | 58 +++++++++++++++ src/scenes/UI/main_menu/main_menu.gd | 47 ++++++++++++ src/scenes/UI/main_menu/main_menu.gd.uid | 1 + src/scenes/UI/main_menu/main_menu.tscn | 78 ++++++++++++++++++++ src/scripts/network/network_handler.gd | 11 ++- src/scripts/singletons/game_manager.gd | 27 +++---- src/scripts/star_system.gd | 20 ++++- 10 files changed, 259 insertions(+), 26 deletions(-) create mode 100644 src/scenes/UI/ingame_menu/ingame_menu.gd create mode 100644 src/scenes/UI/ingame_menu/ingame_menu.gd.uid create mode 100644 src/scenes/UI/ingame_menu/ingame_menu.tscn create mode 100644 src/scenes/UI/main_menu/main_menu.gd create mode 100644 src/scenes/UI/main_menu/main_menu.gd.uid create mode 100644 src/scenes/UI/main_menu/main_menu.tscn diff --git a/src/main.tscn b/src/main.tscn index 9dadab7..846a426 100644 --- a/src/main.tscn +++ b/src/main.tscn @@ -1,6 +1,7 @@ [gd_scene load_steps=2 format=3 uid="uid://dogqi2c58qdc0"] -[ext_resource type="Script" uid="uid://bkcouefvi7iup" path="res://scripts/star_system.gd" id="1_ig7tw"] +[ext_resource type="PackedScene" uid="uid://ojcho3pi3u7n" path="res://scenes/UI/main_menu/main_menu.tscn" id="1_ig7tw"] -[node name="StarSystem" type="Node3D"] -script = ExtResource("1_ig7tw") +[node name="StartMenu" type="Node3D" unique_id=1392183658] + +[node name="MainMenu" parent="." unique_id=2099645465 instance=ExtResource("1_ig7tw")] diff --git a/src/scenes/UI/ingame_menu/ingame_menu.gd b/src/scenes/UI/ingame_menu/ingame_menu.gd new file mode 100644 index 0000000..a67a41d --- /dev/null +++ b/src/scenes/UI/ingame_menu/ingame_menu.gd @@ -0,0 +1,35 @@ +extends Control + +@onready var resume_button: Button = %ResumeButton +@onready var disconnect_button: Button = %DisconnectButton +@onready var quit_button: Button = %QuitButton + +func _ready(): + resume_button.pressed.connect(toggle_menu) + disconnect_button.pressed.connect(_on_disconnect_pressed) + quit_button.pressed.connect(_on_quit_pressed) + + hide() + +func _input(event): + if event.is_action_pressed("ui_cancel"): + toggle_menu() + +func toggle_menu(): + visible = !visible + + if visible: + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) + else: + # Only capture mouse if we are actually playing a pawn + # You might need a smarter check here depending on game state + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + +func _on_disconnect_pressed(): + NetworkHandler.close_connection() + toggle_menu() + # Return to main menu + get_tree().change_scene_to_file("res://main.tscn") + +func _on_quit_pressed(): + get_tree().quit() \ No newline at end of file diff --git a/src/scenes/UI/ingame_menu/ingame_menu.gd.uid b/src/scenes/UI/ingame_menu/ingame_menu.gd.uid new file mode 100644 index 0000000..d5164d9 --- /dev/null +++ b/src/scenes/UI/ingame_menu/ingame_menu.gd.uid @@ -0,0 +1 @@ +uid://2aoy8ivk2hgl diff --git a/src/scenes/UI/ingame_menu/ingame_menu.tscn b/src/scenes/UI/ingame_menu/ingame_menu.tscn new file mode 100644 index 0000000..e52d3f0 --- /dev/null +++ b/src/scenes/UI/ingame_menu/ingame_menu.tscn @@ -0,0 +1,58 @@ +[gd_scene load_steps=2 format=3 uid="uid://pausemenu456"] + +[ext_resource type="Script" uid="uid://2aoy8ivk2hgl" path="res://scenes/UI/ingame_menu/ingame_menu.gd" id="1_pm_script"] + +[node name="IngameeMenu" type="Control" unique_id=8878860] +process_mode = 3 +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_pm_script") + +[node name="ColorRect" type="ColorRect" parent="." unique_id=1882361500] +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.05) + +[node name="CenterContainer" type="CenterContainer" parent="." unique_id=1122355242] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer" unique_id=1948011184] +layout_mode = 2 +theme_override_constants/separation = 15 + +[node name="Label" type="Label" parent="CenterContainer/VBoxContainer" unique_id=214886966] +layout_mode = 2 +theme_override_font_sizes/font_size = 32 +text = "Menu" +horizontal_alignment = 1 + +[node name="ResumeButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1856665966] +unique_name_in_owner = true +custom_minimum_size = Vector2(150, 40) +layout_mode = 2 +text = "Resume" + +[node name="DisconnectButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=4948876] +unique_name_in_owner = true +custom_minimum_size = Vector2(150, 40) +layout_mode = 2 +text = "Disconnect" + +[node name="QuitButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1695513560] +unique_name_in_owner = true +custom_minimum_size = Vector2(150, 40) +layout_mode = 2 +text = "Quit Game" diff --git a/src/scenes/UI/main_menu/main_menu.gd b/src/scenes/UI/main_menu/main_menu.gd new file mode 100644 index 0000000..0373797 --- /dev/null +++ b/src/scenes/UI/main_menu/main_menu.gd @@ -0,0 +1,47 @@ +extends Control + +# @export var lobby_menu: Control +# @export var settings_menu: Control + +# Buttons and input fields +@onready var host_button: Button = %HostButton +@onready var join_button: Button = %JoinButton +@onready var settings_button: Button = %SettingsButton +@onready var quit_button: Button = %QuitButton +@onready var address_entry: LineEdit = %AddressEntry + +func _ready(): + host_button.pressed.connect(_on_host_pressed) + join_button.pressed.connect(_on_join_pressed) + quit_button.pressed.connect(_on_quit_pressed) + + # Ensure we start with a clean slate + # lobby_menu.visible = false + + # If we just returned from a game, ensure mouse is visible + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) + +func _on_host_pressed(): + # For a simple test, hosting immediately starts the server and the game + NetworkHandler.create_server() + NetworkHandler.on_peer_connected(multiplayer.get_unique_id()) + _transition_to_game() + +func _on_join_pressed(): + var ip = address_entry.text + if ip.is_empty(): + ip = "127.0.0.1" # Default to localhost + + NetworkHandler.create_client(ip) + # The NetworkHandler signals will handle the actual transition once connected + # But for UI feedback, we might want to show a "Connecting..." label here. + +func _on_quit_pressed(): + get_tree().quit() + +func _transition_to_game(): + # This would typically load the main game scene. + # Since your main scene IS the game loop currently, we might need to + # just hide the menu if it's an overlay, OR change scenes. + # Assuming Main.tscn is the game world: + get_tree().change_scene_to_file("res://scripts/star_system.tscn") diff --git a/src/scenes/UI/main_menu/main_menu.gd.uid b/src/scenes/UI/main_menu/main_menu.gd.uid new file mode 100644 index 0000000..382ece6 --- /dev/null +++ b/src/scenes/UI/main_menu/main_menu.gd.uid @@ -0,0 +1 @@ +uid://dypq4h3hy1l3v diff --git a/src/scenes/UI/main_menu/main_menu.tscn b/src/scenes/UI/main_menu/main_menu.tscn new file mode 100644 index 0000000..eb96e56 --- /dev/null +++ b/src/scenes/UI/main_menu/main_menu.tscn @@ -0,0 +1,78 @@ +[gd_scene load_steps=2 format=3 uid="uid://ojcho3pi3u7n"] + +[ext_resource type="Script" uid="uid://dypq4h3hy1l3v" path="res://scenes/UI/main_menu/main_menu.gd" id="1_script"] + +[node name="MainMenu" type="Control" unique_id=2099645465] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_script") + +[node name="Background" type="ColorRect" parent="." unique_id=2137889995] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0.05, 0.05, 0.08, 1) + +[node name="CenterContainer" type="CenterContainer" parent="." unique_id=1954458945] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer" unique_id=542164632] +layout_mode = 2 +theme_override_constants/separation = 20 + +[node name="Label" type="Label" parent="CenterContainer/VBoxContainer" unique_id=973405608] +layout_mode = 2 +theme_override_font_sizes/font_size = 48 +text = "Millimeters of Aluminium" +horizontal_alignment = 1 + +[node name="AddressEntry" type="LineEdit" parent="CenterContainer/VBoxContainer" unique_id=994010326] +unique_name_in_owner = true +layout_mode = 2 +placeholder_text = "127.0.0.1" +alignment = 1 + +[node name="HostButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1548149031] +unique_name_in_owner = true +custom_minimum_size = Vector2(200, 50) +layout_mode = 2 +text = "Host Game" + +[node name="JoinButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1826215269] +unique_name_in_owner = true +custom_minimum_size = Vector2(200, 50) +layout_mode = 2 +text = "Join Game" + +[node name="SettingsButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=811999044] +unique_name_in_owner = true +custom_minimum_size = Vector2(200, 50) +layout_mode = 2 +text = "Settings" + +[node name="QuitButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1005717980] +unique_name_in_owner = true +custom_minimum_size = Vector2(200, 50) +layout_mode = 2 +text = "Quit to Desktop" + +[node name="LobbyMenu" type="Control" parent="." unique_id=604668798] +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 diff --git a/src/scripts/network/network_handler.gd b/src/scripts/network/network_handler.gd index 220b26b..14daf08 100644 --- a/src/scripts/network/network_handler.gd +++ b/src/scripts/network/network_handler.gd @@ -71,12 +71,17 @@ func on_peer_disconnected(peer_id: int) -> void: print("Peer %s lost connection to: %s" % [multiplayer.get_unique_id(), peer_id]) # TODO: GameManager should cleanup the player's pawn + GameManager.remove_player_pawn(peer_id) + func on_connected_to_server() -> void: print("%s connected to server!" % multiplayer.get_unique_id()) # If we are in the main menu, this is the trigger to switch scenes - if get_tree().current_scene.name == "MainMenu": - get_tree().change_scene_to_file("res://main.tscn") + if get_tree().current_scene.name == "StartMenu": + print("Transitioning to game scene...") + get_tree().change_scene_to_file("res://scripts/star_system.tscn") + else: + print("Player ID %s: Already in game scene." % multiplayer.get_unique_id()) func on_server_disconnected() -> void: print("Disconnected from server.") - get_tree().change_scene_to_file("res://scenes/UI/main_menu.tscn") \ No newline at end of file + get_tree().change_scene_to_file("res://main.tscn") diff --git a/src/scripts/singletons/game_manager.gd b/src/scripts/singletons/game_manager.gd index a678297..86dde06 100644 --- a/src/scripts/singletons/game_manager.gd +++ b/src/scripts/singletons/game_manager.gd @@ -25,32 +25,25 @@ func _ready(): # This is now expected since we are using 3D scenes directly. print("GameManager: game_config.tres not found or used. Using direct 3D scene references.") return - - # Check command-line arguments to determine if this instance should be a server or client. - # Godot's "Run Multiple Instances" feature adds "--server" to the main instance. - if "--server" in OS.get_cmdline_args(): - NetworkHandler.create_server() - elif "--host" in OS.get_cmdline_args(): - NetworkHandler.create_server() - # Host also acts as a player, so we need to handle its own connection. - NetworkHandler.on_peer_connected.call_deferred(1) - else: - print("GameManager: Starting as CLIENT.") - NetworkHandler.create_client() func _process(_delta): if find_available_spawner(): _try_spawn_waiting_player() -# Called when the game starts (e.g., from _ready() in StarSystemGenerator) -func start_game(): - pass - func queue_spawn_player(player_id: int): waiting_players.append(player_id) print("GameManager: Player %d queued for spawn." % player_id) +func remove_player_pawn(player_id: int): + if player_pawns.has(player_id): + var pawn = player_pawns[player_id] + if is_instance_valid(pawn): + pawn.queue_free() + player_pawns.erase(player_id) + print("GameManager: Removed pawn for player %d." % player_id) + else: + print("GameManager: No pawn found for player %d to remove." % player_id) # function to process the waiting queue. func _try_spawn_waiting_player(): @@ -84,6 +77,8 @@ func _try_spawn_waiting_player(): print("GameManager peer %s: Failed to spawn player %d." % [multiplayer.get_unique_id(), player_id]) func find_available_spawner() -> Spawner: + if not registered_spawners: + return null var idx = registered_spawners.find_custom(func(spawner: Spawner) -> bool: return spawner.can_spawn() ) diff --git a/src/scripts/star_system.gd b/src/scripts/star_system.gd index 4a7b184..8e6138b 100644 --- a/src/scripts/star_system.gd +++ b/src/scripts/star_system.gd @@ -9,6 +9,8 @@ extends Node3D var system_data: SystemData +const PAUSE_MENU_SCENE = preload("res://scenes/UI/ingame_menu/ingame_menu.tscn") + func _ready(): # 1. Create the generator tool. @@ -30,12 +32,22 @@ func _ready(): # We can reconstruct 'system_data' by scanning children if needed, # or just let GameManager find them via 'get_children()'. - # 2. Tell the generator to build the system within this StarSystem node. - - # 3. Register the completed system with the GameManager. + + # 2. Register the completed system with the GameManager. GameManager.register_star_system(self) - GameManager.start_game() + # 3. Instantiate UI (Local Player Only) + if not DisplayServer.get_name() == "headless": + _setup_ui() + + +func _setup_ui(): + var canvas_layer = CanvasLayer.new() + add_child(canvas_layer) + var pause_menu = PAUSE_MENU_SCENE.instantiate() + canvas_layer.add_child(pause_menu) + + # --- Public API for accessing system data --- func get_star() -> OrbitalBody3D: if is_instance_valid(system_data):