昨天碰到了多人控制与位置同步问题, 刚开始提示不能在ready中设置authority, 于是我按照报错提示调整为enter_tree中动态创建输入组件并设置authority, 但又碰到Player同步生成的问题
今天调试了好一会, 一直各种问题, 核对源码没发现任何逻辑上的问题
于是我从头实现了整个项目, 结构, 源码都没怎么动, 它好了...
甚至也没提示在ready中不能设置authority的报错了, 这让人非常不爽, 我不知道问题是怎么好的, 也不知道是怎么出现的, 意味着我没有弄清昨天的情形, 我感到非常困扰
昨天有问题就没提交git, 现在觉得出问题的代码也要加入源码管理, 方便复现当时的场景
如果有细心的朋友从我昨天的文章里面发现蛛丝马迹的错误, 希望立即指出来, 感激不尽!

目前仅涉及到4个简单的场景和脚本
-
main_menu (默认场景)
核心逻辑: 点击Host后创建server并跳转到main场景; 点击Join后创建client, 并在连接server成功后跳转main场景
class_name MainMenu extends Control const PORT : int = 34560 const MAIN = preload("uid://yubvfldj7w73") @onready var host_button: Button = %HostButton @onready var join_button: Button = %JoinButton func _ready() -> void: host_button.pressed.connect(_on_host_pressed) join_button.pressed.connect(_on_join_pressed) multiplayer.connected_to_server.connect(_on_connected_to_server) func _on_host_pressed() -> void: var server_peer := ENetMultiplayerPeer.new() server_peer.create_server(PORT) multiplayer.multiplayer_peer = server_peer get_tree().change_scene_to_packed(MAIN) func _on_join_pressed() -> void: var client_peer := ENetMultiplayerPeer.new() client_peer.create_client("127.0.0.1", PORT) multiplayer.multiplayer_peer = client_peer func _on_connected_to_server() -> void: get_tree().change_scene_to_packed(MAIN) -
main (游戏场景)
在ready中定义spawn_function, 并调用rpc通知server同步生成player
extends Node const PLAYER = preload("uid://dgstmloeo60yy") @onready var level: Node2D = $Level @onready var player_spawner: MultiplayerSpawner = %PlayerSpawner func _ready() -> void: player_spawner.spawn_function = func(data): print("[peer %s] Spawn player: %s" % [multiplayer.get_unique_id(), data.peer_id]) var player = PLAYER.instantiate() player.name = "Player%s" % [data.peer_id] player.input_peer_id = data.peer_id return player _create_player.rpc_id(1) @rpc("any_peer", "call_local", "reliable") func _create_player() -> void: var sender_id := multiplayer.get_remote_sender_id() player_spawner.spawn({ "peer_id": sender_id }) -
player
并在ready中设置input组件的authority, 区分控制权限
extends CharacterBody2D var input_peer_id : int var move_vector: Vector2 = Vector2.ZERO var move_speed: float = 100.0 @onready var player_input_multiplayer_synchronizer_component: PlayerInputMultiplayerSynchronizerComponent = $PlayerInputMultiplayerSynchronizerComponent func _ready() -> void: print("[peer %s] Set player(%s) input authroity %s" % [multiplayer.get_unique_id(), name, input_peer_id]) player_input_multiplayer_synchronizer_component.set_multiplayer_authority(input_peer_id) func _process(_delta: float) -> void: var input := player_input_multiplayer_synchronizer_component.move_vector velocity = input * move_speed move_and_slide() -
input_component (player_input_multiplayer_synchronizer_component)
获取输入, 在属性同步列表中同步move_vector
class_name PlayerInputMultiplayerSynchronizerComponent extends MultiplayerSynchronizer var move_vector : Vector2 = Vector2.ZERO func _process(_delta: float) -> void: if is_multiplayer_authority(): move_vector = Input.get_vector("move_left", "move_right", "move_up", "move_down")