Godot 4多人RPG游戏主机与客户端建筑同步异常问题求助
多人RPG游戏网格系统物品放置同步异常问题求助
问题现象
- 主机放置物品后仅自身可见,编辑器Remote标签页的PlayerBuildings节点下无显示
- 客户端放置物品后仅自身可见,Remote标签页有显示
报错信息
get_node: Node not found:"World/PlayerBuildings/@Camp1@3/MultiplayerSynchronizer" process_simplify_path: Condition "node == nullptr" is true.
节点树截图
网格系统代码
extends Node2D @onready var camp_fire = preload("res://src/Scenes/camp.tscn") var tile_size =16 enum {OBSTACTLE, COLLECTABLE,RESOURCE} var grid_size = Vector2(160,160) var grid = [] func _ready(): for x in range(grid_size.x): grid.append([]) for y in range(grid_size.y): grid[x].append(null) var positions = [] for i in range (50): var xcoor = (randi() % int(grid_size.x)) var ycoor = (randi() % int(grid_size.y)) var grid_pos = Vector2(xcoor,ycoor) if not grid_pos in positions: positions.append(grid_pos) func _input(event): if GameManager.enable: if event.is_action_pressed("LeftClick"): var mouse_pos = get_global_mouse_position() var multiX = int(round(mouse_pos.x)/tile_size) var numX = multiX*tile_size var multiY = int(round(mouse_pos.y)/tile_size) var numY = multiY*tile_size var new_pos = Vector2(multiX, multiY) var new_camp_fire = camp_fire.instantiate() new_camp_fire.name = str(new_camp_fire.name + str(multiplayer.get_unique_id()) ) new_camp_fire.set_position(tile_size*new_pos) grid[multiX][multiY] = OBSTACTLE get_tree().root.get_node("World").get_node("PlayerBuildings").add_child(new_camp_fire)
解决方案
1. 切换到权威服务器架构
Godot多人游戏必须遵循服务器权威原则,所有节点创建/销毁操作由服务器统一处理,客户端仅发送请求,避免本地实例化导致的不同步。修改代码如下:
extends Node2D @onready var camp_fire = preload("res://src/Scenes/camp.tscn") var tile_size =16 enum {OBSTACTLE, COLLECTABLE,RESOURCE} var grid_size = Vector2(160,160) var grid = [] func _ready(): for x in range(grid_size.x): grid.append([]) for y in range(grid_size.y): grid[x].append(null) var positions = [] for i in range (50): var xcoor = (randi() % int(grid_size.x)) var ycoor = (randi() % int(grid_size.y)) var grid_pos = Vector2(xcoor,ycoor) if not grid_pos in positions: positions.append(grid_pos) func _input(event): if GameManager.enable: if event.is_action_pressed("LeftClick"): var mouse_pos = get_global_mouse_position() var multiX = int(round(mouse_pos.x)/tile_size) var multiY = int(round(mouse_pos.y)/tile_size) var grid_pos = Vector2(multiX, multiY) # 客户端请求服务器放置,服务器直接执行 if multiplayer.is_client(): rpc("request_place_campfire", grid_pos) else: if grid[grid_pos.x][grid_pos.y] == null: place_campfire(grid_pos) # 允许任意节点调用的RPC,仅服务器处理逻辑 @rpc("any_peer") func request_place_campfire(grid_pos): if multiplayer.is_server() and grid[grid_pos.x][grid_pos.y] == null: place_campfire(grid_pos) # 服务器统一执行的放置逻辑 func place_campfire(grid_pos): var new_camp_fire = camp_fire.instantiate() new_camp_fire.name = str(new_camp_fire.name + str(multiplayer.get_unique_id())) new_camp_fire.set_position(tile_size * grid_pos) new_camp_fire.set_network_master(1) # 设置服务器为节点主控 grid[grid_pos.x][grid_pos.y] = OBSTACTLE get_tree().root.get_node("World/PlayerBuildings").add_child(new_camp_fire)
2. 修复MultiplayerSynchronizer报错
- 打开
camp.tscn,确保场景根节点下包含MultiplayerSynchronizer节点 - 配置同步器的
Properties列表,添加需要同步的属性(比如position、visible等) - 检查节点路径:确保同步器的
Root Path设置正确,避免找不到节点的报错
3. 同步网格状态
服务器维护唯一的网格数据,客户端需要通过RPC同步网格状态,避免本地网格与服务器不一致。可以在服务器放置物品后,广播网格更新:
# 在place_campfire函数末尾添加 rpc("sync_grid_update", grid_pos, OBSTACTLE) @rpc("all") func sync_grid_update(grid_pos, tile_type): grid[grid_pos.x][grid_pos.y] = tile_type
4. 验证Remote标签页显示
修改后,服务器(主机)创建的节点会出现在Remote标签页的PlayerBuildings下,所有客户端会同步显示该节点,解决之前的可见性不一致问题。
内容的提问来源于stack exchange,提问作者nicktehboy meny
相关产品推荐
相关产品推荐

