extends Node3D ## 世界根节点。 ## ## 只做一件事:把玩家场景注册给 MultiplayerSpawner,并把 spawner 托管给 Net 单例。 ## 玩家的生成/回收时机完全由 Net 决定,本文件不主动调用 spawn。 const PLAYER_SCENE: PackedScene = preload("res://player/player.tscn") const PLAYER_GROUP: String = "net_player" ## 用节点路径而不是全局标识符访问单例: ## autoload 的全局名只在引擎启动时注册,这样写不依赖注册时机。 const NET_PATH: String = "/root/Net" @onready var spawner: MultiplayerSpawner = $MultiplayerSpawner func _ready() -> void: spawner.spawn_function = _create_player var net := get_node_or_null(NET_PATH) if net != null: net.bind_spawner(spawner) else: push_error("Net 单例未注册,联机不可用。请确认 project.godot 的 [autoload] 里有 Net") ## MultiplayerSpawner 会在**每一端**都调用这个函数,因此 authority 必须在这里设置: ## 这样「谁是本地玩家」在各端结论一致,玩家脚本里的 is_multiplayer_authority() 才可靠。 ## recursive=true 很关键 —— 节点 authority 不自动继承,Sync 子节点必须一起设。 func _create_player(peer_id: int) -> Node: var player := PLAYER_SCENE.instantiate() player.name = str(peer_id) player.add_to_group(PLAYER_GROUP) player.set_multiplayer_authority(peer_id, true) var here := multiplayer.get_unique_id() print("[Net] 本端 %d 生成玩家 %d%s" % [here, peer_id, "(本地操控)" if peer_id == here else "(远端回放)"]) return player