Files
agame/world/main.gd
T
2026-10-16 16:01:18 +08:00

46 lines
2.3 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Node3D
## 世界根节点。
##
## 只做一件事:把玩家场景注册给 MultiplayerSpawner,并把 spawner 托管给 Net 单例。
## 玩家的生成/回收时机完全由 Net 决定,本文件不主动调用 spawn。
@export
var player_scene: PackedScene
const PLAYER_GROUP: String = "net_player"
## 用节点路径而不是全局标识符访问单例:
## autoload 的全局名只在引擎启动时注册,这样写不依赖注册时机。
const NET_PATH: String = "/root/Net"
@onready var spawner: MultiplayerSpawner = $MultiplayerSpawner
@onready var player_spawn_pos: Node3D = $PlayerSpawnPos
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()
# ⚠ 这里只能写**局部** position,绝对不能写 global_position:
# spawn_function 返回的节点还没入树(spawner 之后才 add_child),而 Node3D 的
# global_transform 在未入树时是无效的 —— get_global_transform() 会 ERR_FAIL 并回退成
# 单位矩阵,于是 set_global_transform() 把 Player 根节点的基连同**缩放一起换成单位阵**:
# player.tscn 根节点那层 0.096096(老鼠 0.15 m 的关键)被静默抹掉,
# 实测后果 —— 老鼠从 0.15 m 涨到 1.56 m,第一人称相机从脚底 0.1116 m 抬到 1.161 m。
# Main 与 PlayerSpawnPos 同级、且 Main 本身无变换,所以局部坐标就等于世界坐标。
player.position = player_spawn_pos.position
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