feat: adding basic multiplayer

This commit is contained in:
DottsGit
2026-06-06 13:28:43 -04:00
parent 59096d322a
commit aefed46daf
6 changed files with 312 additions and 12 deletions
+215 -3
View File
@@ -2,6 +2,10 @@ extends Control
var _ui_vbox: VBoxContainer
var _level_selector_panel: VBoxContainer
var _multiplayer_panel: VBoxContainer
var _direct_connect_panel: VBoxContainer
var _host_lobby_panel: Control
var _host_lobby_players_list: ItemList
func _ready() -> void:
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
@@ -97,7 +101,157 @@ func _ready() -> void:
_add_button(_level_selector_panel, "Back", _on_back_pressed)
func _build_level_card(parent: Container, title: String, scene_path: String, gradient: Gradient) -> void:
# ==========================================
# MULTIPLAYER PANEL
# ==========================================
_multiplayer_panel = VBoxContainer.new()
_multiplayer_panel.add_theme_constant_override("separation", 20)
_multiplayer_panel.set_anchor_and_offset(SIDE_LEFT, 0.0, 50)
_multiplayer_panel.set_anchor_and_offset(SIDE_TOP, 0.0, 50)
_multiplayer_panel.set_anchor_and_offset(SIDE_RIGHT, 0.0, 600)
_multiplayer_panel.set_anchor_and_offset(SIDE_BOTTOM, 1.0, -50)
_multiplayer_panel.hide()
add_child(_multiplayer_panel)
var mp_title = Label.new()
mp_title.text = "Multiplayer"
mp_title.add_theme_font_size_override("font_size", 64)
mp_title.add_theme_color_override("font_color", Color(1, 1, 1))
mp_title.add_theme_color_override("font_outline_color", Color(0, 0, 0))
mp_title.add_theme_constant_override("outline_size", 8)
_multiplayer_panel.add_child(mp_title)
var mp_spacer = Control.new()
mp_spacer.custom_minimum_size = Vector2(0, 20)
_multiplayer_panel.add_child(mp_spacer)
_add_button(_multiplayer_panel, "Host Game", _on_host_pressed)
_add_button(_multiplayer_panel, "Direct Connect", _on_direct_connect_pressed)
_add_button(_multiplayer_panel, "Back", _on_multiplayer_back_pressed)
# ==========================================
# DIRECT CONNECT PANEL
# ==========================================
_direct_connect_panel = VBoxContainer.new()
_direct_connect_panel.add_theme_constant_override("separation", 20)
_direct_connect_panel.set_anchor_and_offset(SIDE_LEFT, 0.0, 50)
_direct_connect_panel.set_anchor_and_offset(SIDE_TOP, 0.0, 50)
_direct_connect_panel.set_anchor_and_offset(SIDE_RIGHT, 0.0, 600)
_direct_connect_panel.set_anchor_and_offset(SIDE_BOTTOM, 1.0, -50)
_direct_connect_panel.hide()
add_child(_direct_connect_panel)
var dc_title = Label.new()
dc_title.text = "Direct Connect"
dc_title.add_theme_font_size_override("font_size", 64)
dc_title.add_theme_color_override("font_color", Color(1, 1, 1))
dc_title.add_theme_color_override("font_outline_color", Color(0, 0, 0))
dc_title.add_theme_constant_override("outline_size", 8)
_direct_connect_panel.add_child(dc_title)
var dc_ip_label = Label.new()
dc_ip_label.text = "IP Address:"
dc_ip_label.add_theme_font_size_override("font_size", 24)
_direct_connect_panel.add_child(dc_ip_label)
var dc_ip_input = LineEdit.new()
dc_ip_input.text = "127.0.0.1"
dc_ip_input.name = "IPInput"
dc_ip_input.add_theme_font_size_override("font_size", 24)
dc_ip_input.custom_minimum_size = Vector2(300, 50)
_direct_connect_panel.add_child(dc_ip_input)
var dc_port_label = Label.new()
dc_port_label.text = "Port:"
dc_port_label.add_theme_font_size_override("font_size", 24)
_direct_connect_panel.add_child(dc_port_label)
var dc_port_input = LineEdit.new()
dc_port_input.text = "31415" # Default Port
dc_port_input.name = "PortInput"
dc_port_input.add_theme_font_size_override("font_size", 24)
dc_port_input.custom_minimum_size = Vector2(300, 50)
_direct_connect_panel.add_child(dc_port_input)
var dc_spacer = Control.new()
dc_spacer.custom_minimum_size = Vector2(0, 20)
_direct_connect_panel.add_child(dc_spacer)
_add_button(_direct_connect_panel, "Connect", _on_connect_confirm_pressed)
_add_button(_direct_connect_panel, "Back", _on_dc_back_pressed)
# ==========================================
# HOST LOBBY PANEL
# ==========================================
_host_lobby_panel = Control.new()
_host_lobby_panel.set_anchors_preset(Control.PRESET_FULL_RECT)
_host_lobby_panel.hide()
add_child(_host_lobby_panel)
var hl_hbox = HBoxContainer.new()
hl_hbox.set_anchors_preset(Control.PRESET_FULL_RECT)
hl_hbox.add_theme_constant_override("separation", 50)
_host_lobby_panel.add_child(hl_hbox)
# Left Side (Level Selector)
var hl_left = VBoxContainer.new()
hl_left.size_flags_horizontal = Control.SIZE_EXPAND_FILL
hl_left.set_anchor_and_offset(SIDE_LEFT, 0.0, 50)
hl_left.set_anchor_and_offset(SIDE_TOP, 0.0, 50)
hl_left.add_theme_constant_override("separation", 20)
var hl_margin = MarginContainer.new()
hl_margin.add_theme_constant_override("margin_left", 50)
hl_margin.add_theme_constant_override("margin_top", 50)
hl_margin.add_theme_constant_override("margin_bottom", 50)
hl_margin.size_flags_horizontal = Control.SIZE_EXPAND_FILL
hl_hbox.add_child(hl_margin)
hl_margin.add_child(hl_left)
var hl_title = Label.new()
hl_title.text = "Host Lobby - Select Level"
hl_title.add_theme_font_size_override("font_size", 64)
hl_title.add_theme_color_override("font_color", Color(1, 1, 1))
hl_title.add_theme_color_override("font_outline_color", Color(0, 0, 0))
hl_title.add_theme_constant_override("outline_size", 8)
hl_left.add_child(hl_title)
var hl_cards = HBoxContainer.new()
hl_cards.add_theme_constant_override("separation", 30)
hl_left.add_child(hl_cards)
_build_level_card(hl_cards, "Dust 2", "res://scenes/dust2_level/dust2_level.tscn", d2_gradient, true)
_build_level_card(hl_cards, "Test Level", "res://scenes/test_level/test_level.tscn", tl_gradient, true)
var hl_spacer = Control.new()
hl_spacer.size_flags_vertical = Control.SIZE_EXPAND_FILL
hl_left.add_child(hl_spacer)
_add_button(hl_left, "Disband & Back", _on_lobby_back_pressed)
# Right Side (Player List)
var hl_right = VBoxContainer.new()
hl_right.custom_minimum_size = Vector2(400, 0)
var hl_right_margin = MarginContainer.new()
hl_right_margin.add_theme_constant_override("margin_top", 50)
hl_right_margin.add_theme_constant_override("margin_right", 50)
hl_right_margin.add_theme_constant_override("margin_bottom", 50)
hl_hbox.add_child(hl_right_margin)
hl_right_margin.add_child(hl_right)
var pl_title = Label.new()
pl_title.text = "Players Connected"
pl_title.add_theme_font_size_override("font_size", 48)
pl_title.add_theme_color_override("font_outline_color", Color(0, 0, 0))
pl_title.add_theme_constant_override("outline_size", 8)
hl_right.add_child(pl_title)
_host_lobby_players_list = ItemList.new()
_host_lobby_players_list.size_flags_vertical = Control.SIZE_EXPAND_FILL
_host_lobby_players_list.add_theme_font_size_override("font_size", 24)
hl_right.add_child(_host_lobby_players_list)
func _build_level_card(parent: Container, title: String, scene_path: String, gradient: Gradient, is_multiplayer: bool = false) -> void:
var btn = TextureButton.new()
btn.custom_minimum_size = Vector2(300, 400)
@@ -137,7 +291,10 @@ func _build_level_card(parent: Container, title: String, scene_path: String, gra
lbl.set_anchors_preset(Control.PRESET_FULL_RECT)
overlay.add_child(lbl)
btn.pressed.connect(func(): get_tree().change_scene_to_file(scene_path))
if is_multiplayer:
btn.pressed.connect(func(): get_node("/root/NetworkManager").rpc_load_level.rpc(scene_path))
else:
btn.pressed.connect(func(): get_tree().change_scene_to_file(scene_path))
parent.add_child(btn)
@@ -159,7 +316,62 @@ func _on_singleplayer_pressed() -> void:
_level_selector_panel.show()
func _on_multiplayer_pressed() -> void:
print("Multiplayer not implemented yet.")
_ui_vbox.hide()
_multiplayer_panel.show()
func _on_multiplayer_back_pressed() -> void:
_multiplayer_panel.hide()
_ui_vbox.show()
func _on_host_pressed() -> void:
_multiplayer_panel.hide()
_host_lobby_panel.show()
var nm = get_node("/root/NetworkManager")
nm.host_game()
_update_lobby_players()
if not nm.player_connected.is_connected(_on_network_player_connected):
nm.player_connected.connect(_on_network_player_connected)
nm.player_disconnected.connect(_on_network_player_disconnected)
func _on_direct_connect_pressed() -> void:
_multiplayer_panel.hide()
_direct_connect_panel.show()
func _on_dc_back_pressed() -> void:
_direct_connect_panel.hide()
_multiplayer_panel.show()
func _on_connect_confirm_pressed() -> void:
var ip = _direct_connect_panel.get_node("IPInput").text
var port = _direct_connect_panel.get_node("PortInput").text.to_int()
get_node("/root/NetworkManager").join_game(ip, port)
# For simplicity, we can show a connecting label or just wait for the game to start via RPC
func _on_lobby_back_pressed() -> void:
_host_lobby_panel.hide()
_multiplayer_panel.show()
var nm = get_node("/root/NetworkManager")
nm.disconnect_game()
if nm.player_connected.is_connected(_on_network_player_connected):
nm.player_connected.disconnect(_on_network_player_connected)
nm.player_disconnected.disconnect(_on_network_player_disconnected)
func _on_network_player_connected(_id: int) -> void:
_update_lobby_players()
func _on_network_player_disconnected(_id: int) -> void:
_update_lobby_players()
func _update_lobby_players() -> void:
if not _host_lobby_players_list: return
_host_lobby_players_list.clear()
var nm = get_node("/root/NetworkManager")
var host_name = SettingsManager.username
for pid in nm.connected_players:
if pid == 1:
_host_lobby_players_list.add_item(host_name + " (Host)")
else:
_host_lobby_players_list.add_item("Player " + str(pid))
func _on_loadouts_pressed() -> void:
if has_node("/root/PauseMenu"):