Hello, im trying to create multiplayer test chamber, but somehow i dont understand why camera3D works only on one player instance.
As you can see the one on the left is host and on the right is +1 player.
Game spawns players both at separate coordinates. Host can control his camera but the client cant.
Also When i spawn (instantiate) new nodes (Items) i add them to the World node as child. But they dont show up in the other player screen.
Also if i pick up item, it dont show up on other players screen. Item picked up and its position is changed to the pickers hand position.
One thing that comes to mind is adding the MultiplayerSync node to the Item Nodes and add the transform path to sync.
But why camera controls not working? I mean the camera is a child of the player node. Also one thing i noticed that the player on the right controls the Top down camera for some reason, it rotates as i move mouse. But it should work on host player too and it does not.
The main camera is a child of "h" node
The topdown camera is child of "UIRoot" control node
"h" node is set top_level true, and i got function that moves it around and that fun is called from _physics_process():
From what i understood is that at the top of the physics_process function i check if the current instnace is the player if not then do not move player. It works for the WASD movements but not camera .
If i add "h" nodes position/transform as synchronizer property then the host will control both player cameras at the same time, which is not what needs to happen.
So items spawn works from one player to other but not from other to one. Not sure.. also mouse position intersection in the 3d world is not correct, it seems it gets other players position.. not current session players position.
Rewritten the whole thing from scratch.. almost there..
One thing left to do is to sync the client (other player) mouse position. My item spawns in the direction where the player is looking (camera) so idk why the item on the client (other player) spawns not in the direction of where he looks.
## more code
func _enter_tree() -> void:
set_multiplayer_authority(str(name).to_int())
pass
func _ready():
if not is_multiplayer_authority(): return
## more code
camera_3d.current = true
func _unhandled_input(_event):
if not is_multiplayer_authority(): return
## more code
if Input.is_action_just_pressed("action_throw"):
spawn_item.rpc()
## more code
func _input(event):
if not is_multiplayer_authority(): return
## more code
func _physics_process(delta):
if not is_multiplayer_authority(): return
## more code
@rpc("any_peer","call_local")
func spawn_item():
var basis_z = camera_3d.global_transform.basis.z
var g_t = global_transform
spawn_item_signal.emit(g_t, basis_z)
pass
## more code
Note the spawn_item is my own function, so just insert your code there or adjust to your needs. Its just a demonstration how it works.
MultiplayerSynchronizer
Had to add Camera3Dglobal_transform to get the spawn_item to receive the correct transform value, otherwise i was getting vec3(0,0,1)
Box.tscn
No script in that scene
MultiplayerSynchronizer
world.tscn
I messed up here but it still works. I placed the Players node underMultiplayerSpawner. Players node should be a child of the World node. But if you reference it in the code it still works as you saw in the video above.
Add scenes to the spawner list. You can add player scene too but i instantiate players on _ready() function of the World node so i dont need it atm. but you will need it once you start adding functionality for when you want players join mid game, when server is running.
World script just contains code to spawn player -> instantiate player scene, add child to Players node. Also i got code here for spawn_item,
world.gd
extends Node3D
const PLAYER = preload("res://Assets/Player/player.tscn")
const BOX = preload("res://Assets/Items/box.tscn")
@onready var players: Node = $MultiplayerSpawner/Players
const start_pos: Vector3 = Vector3(0,3,0)
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
var index =0
for i in GameManager.players:
spawn_player(GameManager.players[i])
index +=1
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass
func spawn_item_world(player_transform:Transform3D, basis_z:Vector3):
var new_box = BOX.instantiate()
new_box.position = player_transform.origin - (basis_z * 3)
add_child(new_box)
pass
func spawn_player(player_data:PlayerData):
var new_pos:Vector3
var new_player = PLAYER.instantiate()
new_player.name = str(player_data.id)
new_player.player_data=player_data
players.add_child(new_player)
new_player.spawn_item_signal.connect(spawn_item_world)
var player_count = players.get_children().size()
if player_count > 1:
var last_player = players.get_children()[player_count-1]
new_pos = last_player.position + Vector3(3,3,3)
new_player.position = new_pos
else:
new_player.position = start_pos
MultiplayerUI.tscn <- entry point for the game
MultiplayerUI.gd
extends Control
@export var address = "127.0.0.1"
@export var port = 8910
var peer:ENetMultiplayerPeer
@onready var host: Button = $VBoxContainer/Host
@onready var join: Button = $VBoxContainer/Join
@onready var start: Button = $VBoxContainer/Start
@onready var player_name: LineEdit = $VBoxContainer/HBoxContainer/PlayerName
const WORLD = preload("res://Assets/World/world.tscn")
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
multiplayer.peer_connected.connect(peer_connected)
multiplayer.peer_disconnected.connect(peer_disconnected)
multiplayer.connected_to_server.connect(connected_to_server)
multiplayer.connection_failed.connect(connection_failed)
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass
# this gets called on server and clients
func peer_connected(id):
print("Player connected: ", id)
pass
# this gets called on server and clients
func peer_disconnected(id):
print("Player disconnected: ", id)
pass
# called only from clients
func connected_to_server():
print("Connected to server!")
send_player_info.rpc_id(1,player_name.text,multiplayer.get_unique_id())
pass
# called only from clients
func connection_failed(id):
print("Player connection failed: ", id)
pass
@rpc("any_peer")
func send_player_info(name, id):
if !GameManager.players.has(id):
var new_player_data:PlayerData = PlayerData.new()
new_player_data.id=id
new_player_data.player_name=name
new_player_data.score = 0.0
GameManager.players[id]=new_player_data
#GameManager.players[id] = {
#"name":name,
#"id":id,
#"score": 0
#}
if multiplayer.is_server():
for i in GameManager.players:
send_player_info.rpc(GameManager.players[i].player_name,i)
pass
@rpc("any_peer","call_local")
func start_game():
var scene = WORLD.instantiate()
get_tree().root.add_child(scene)
self.hide()
pass
func _on_host_button_down() -> void:
peer = ENetMultiplayerPeer.new()
var error = peer.create_server(port, 3)
if error != OK:
print("ERROR - Cannot host: ", error)
return
peer.get_host().compress(ENetConnection.COMPRESS_RANGE_CODER)
multiplayer.set_multiplayer_peer(peer)
print("Waiting for players!")
send_player_info(player_name.text,multiplayer.get_unique_id())
pass # Replace with function body.
func _on_join_button_down() -> void:
peer = ENetMultiplayerPeer.new()
peer.create_client(address,port)
peer.get_host().compress(ENetConnection.COMPRESS_RANGE_CODER)
multiplayer.set_multiplayer_peer(peer)
print("Waiting for players!")
pass # Replace with function body.
func _on_start_button_down() -> void:
start_game.rpc()
pass # Replace with function body.
GameManager.gd <- autoload script to keep player data global
kuligs2 Wait a second is that Hogger? Are you trying to make WoW kinda game / engine here eventually? I come from a lot of WoW dev (and more beyond): https://www.deviantart.com/withinamnesia/art/Game-Master-Veldryn-858651305 . So I have some working ARPG / multiplayer Godot 4+ working demos. Yet I'm trying to get closer to a WoW engine / Baldur's Gate / Zelda / Diablo engine that work with multiplayer and is MIT. Godot 4+ in theory should be able to make these kinds of game engines and the community can make BIG style games with them. I have a lot of experience modding Baldur's Gate and WoW but they are both proprietary game engines an I get in trouble if I work with WoW so its a struggle lol. https://github.com/WithinAmnesia/ARPG/discussions/16
Are you trying to make an M.M.O.R.P.G. sort of engine? I have this kind of goal being worked on but I also want a 2D multiplayer engine that can work like this as well for 2D is much easy to make assets for than 3D and 8 2D games can be made for 1 3D game for MIT / CC0 open source assets of pretty good quality. + https://foozlecc.itch.io/lucifer-exterior-tileset + https://foozlecc.itch.io/lucifer-warrior + https://foozlecc.itch.io/lucifer-lava-dungeon-tileset . Currently there is a lack of a robust Godot 4+ multiplayer ARPG / MMORPG MIT license forever free open source community tool set / example / project / demonstration.
All thoughts and suggestions are welcome. How to make all these cool multiplayer rpg / game engines eh? Bit by bit but some demos and working zone to zone travel would help lol; what should be done lol?
It's really nice to see the community work together to help everyone yay teamwork makes the dreamwork. I hope I can help somehow too. Are there ant MIT github repos around to look at / bug test / tinker with for these multiplayer projects?