Godot Version
4.3
Hi guys!
I’m working to develop a small multiplayer game and I’ve followed a few tutorials and I’ve done and redone some tests with mock projects so I’m getting familiar with the basics.
So I can get a server running and a client connecting to it. Everything is synchronized and working as expected.
I still have trouble undestanding some stuff though but here is my question : I’d like the player to be able to choose between different characters (ships in my game) but I can’t get it done! I’ve tried several things but to no success.
Yesterday, I tried from a blank project and I got stuck again.
Here is my connection scene :
along with the main scene tree :
and the code :
extends Node
var peer
var port = 8080
var ip = "127.0.0.1"
var player_ship : String = "error"
@onready var ship_blue = preload("res://ship_blue.tscn")
@onready var ship_green = preload("res://ship_green.tscn")
@onready var level1 = preload("res://level_1.tscn")
func _ready() -> void:
pass
#multiplayer.peer_connected.connect(peer_connected.bind(player_ship))
func button_blue_ship() :
player_ship = "blue"
if not multiplayer.peer_connected.is_connected(peer_connected) :
multiplayer.peer_connected.connect(peer_connected.bind(player_ship))
else :
print("Already connected to signal")
func button_green_ship() :
player_ship = "green"
if not multiplayer.peer_connected.is_connected(peer_connected) :
multiplayer.peer_connected.connect(peer_connected.bind(player_ship))
else :
print("Already connected to signal")
func host() :
print("hosting")
peer = ENetMultiplayerPeer.new()
peer.create_server(port)
multiplayer.multiplayer_peer = peer
func join() :
print("joining")
peer = ENetMultiplayerPeer.new()
peer.create_client(ip, port)
multiplayer.multiplayer_peer = peer
func peer_connected(id, ship) :
print("Peer connected : ", id, " with ", ship )
As you can see, I’m just printing stuff and the result I get is the contrary of what I expect : Here is the output when I choose BlueShip for the Server and GreenShip for the client
hosting
Peer connected : 1718136004 with blue
joining
Peer connected : 1 with green
So what am I doing wrong?? What is the general way of doing that? Should the player choose their character after the connection was established or before?
Should I put the information in an autoload?
Is it even an Ok solution to put the signal connection in a button_press function?
Thanks a lot for your help!
I’ve continued working on the script and as I was doubtful about a signal connection in a button_press function, I rewrote it along with the _load_player function.
extends Node
var peer
var port = 8080
var ip = "127.0.0.1"
var player_ship : String = "error"
@onready var ship_blue = preload("res://ship_blue.tscn")
@onready var ship_green = preload("res://ship_green.tscn")
@onready var level1 = preload("res://level_1.tscn")
func _ready() -> void:
pass
#multiplayer.peer_connected.connect(peer_connected.bind(player_ship))
func choose_blue_ship() :
player_ship = "blue"
func choose_green_ship() :
player_ship = "green"
func host() :
print("hosting")
peer = ENetMultiplayerPeer.new()
var error = peer.create_server(port)
if error != OK :
print("Can not create Server ", error)
return
multiplayer.multiplayer_peer = peer
multiplayer.peer_connected.connect(peer_connected.bind(player_ship))
_load_player(multiplayer.get_unique_id(),player_ship)
print("Host_pressed : ", multiplayer.get_unique_id(), " ", player_ship)
func join() :
print("joining")
peer = ENetMultiplayerPeer.new()
peer.create_client(ip, port)
multiplayer.multiplayer_peer = peer
func peer_connected(id, play_ship) :
print("Peer connected : ", id, " with ", play_ship )
_load_player(id, play_ship)
func _load_player(id, ship) :
if is_multiplayer_authority() :
var spawn_node = get_tree().current_scene.get_node("Player")
var sh
if ship == "error" :
print("ERROR : Choose a Ship")
return
if ship == "blue" :
sh = ship_blue.instantiate()
sh.player_id = id
sh.name = "Player_" + str(id)
sh.global_position = Vector2(randi_range(50, 450),randi_range(50, 450) )
elif ship == "green" :
sh = ship_green.instantiate()
sh.player_id = id
sh.name = "Player_" + str(id)
sh.global_position = Vector2(randi_range(50, 450),randi_range(50, 450) )
spawn_node.add_child(sh, true)
CCL : I still don’t get the result I’m looking for : the Client spawns the same ship character as the Server regardless of what I choose in the connection window…
Does it come from the signal connection line being in the host() function and the “player_ship” variable having been already passed through?
If that’s the case, how should I do it? What would be a standard procedure for that?
Hi, I continued my work and I finally found the solution which I post here in case someone is interested :
extends Node
var peer
var port = 8080
var ip = "127.0.0.1"
var player_ship : String = "error"
@onready var ship_blue = preload("res://ship_blue.tscn")
@onready var ship_green = preload("res://ship_green.tscn")
@onready var ship_class = preload("res://ShipClass.tscn")
@onready var level1 = preload("res://level_1.tscn")
func _ready() -> void:
get_tree().paused = true
func host() :
print("hosting")
$ConnectionUI/Panel/VBoxContainer/Join.disabled = true
peer = ENetMultiplayerPeer.new()
var error = peer.create_server(port)
if error != OK :
print("Can not create Server ", error)
return
multiplayer.multiplayer_peer = peer
multiplayer.peer_connected.connect(peer_connected)
print("Host_pressed : ", multiplayer.get_unique_id())
func join() :
print("joining")
$ConnectionUI/Panel/VBoxContainer/Host.disabled = true
peer = ENetMultiplayerPeer.new()
peer.create_client(ip, port)
multiplayer.multiplayer_peer = peer
func peer_connected(id) :
print("Peer connected : ", id)
func choose_blue_ship() :
player_ship = "blue"
await get_tree().create_timer(0.2).timeout
print(multiplayer.get_unique_id())
print(player_ship)
if multiplayer.is_server() :
_load_player(multiplayer.get_unique_id(), player_ship)
else :
_load_player.rpc(multiplayer.get_unique_id(), player_ship)
func choose_green_ship() :
player_ship = "green"
await get_tree().create_timer(0.5).timeout
print(multiplayer.get_unique_id())
print(player_ship)
if multiplayer.is_server() :
_load_player(multiplayer.get_unique_id(), player_ship)
else :
_load_player.rpc(multiplayer.get_unique_id(), player_ship)
@rpc("any_peer")
func _load_player(id, ship) :
if is_multiplayer_authority() :
var spawn_node = get_tree().current_scene.get_node("Player")
var sh
if ship != "blue" and ship != "green" :
print("ERROR : Choose a Ship")
return
if ship == "blue" :
sh = ship_blue.instantiate()
sh.player_id = id
sh.name = "Player_" + str(id)
sh.global_position = Vector2(randi_range(50, 450),randi_range(50, 450) )
print("Authority : ", sh.get_multiplayer_authority())
print("Input Authority : ", sh.get_node("InputSynchronizer").get_multiplayer_authority())
spawn_node.add_child(sh, true)
elif ship == "green" :
sh = ship_green.instantiate()
sh.player_id = id
sh.name = "Player_" + str(id)
sh.global_position = Vector2(randi_range(50, 450),randi_range(50, 450) )
print("Authority : ", sh.get_multiplayer_authority())
print("Input Authority : ", sh.get_node("InputSynchronizer").get_multiplayer_authority())
spawn_node.add_child(sh, true)
func _on_connect_pressed() -> void:
hide_ui.rpc()
get_tree().paused = false
@rpc("any_peer", "call_local")
func hide_ui() :
$ConnectionUI.hide()
So I turned the _load_player function into an RPC which I call only on the client and I load the player in the Press_button functions now…
Well, everything works as intended now so I hope I won’t make the same mistake again!
I’m sure there are some better and more efficient way to do it but that’s the one I found by myself and it works so I’ll be happy for now.
Of course, if you have advice, don’t hesitate, I’'ll give my full attention!
Cheers