9.1 多人网络:高层接口与同步策略


9.1 多人网络:高层接口与同步策略

本节摘要:多人架构第一决策是权威模型——对等结构省服务器、专用服结构防作弊,按游戏类型取舍。高层网络接口用注解标注可远程调用的方法,配合唯一的端点与节点路径实现跨端执行;状态同步用复制加插值掩盖延迟。本节合并讲解高层接口与底层传输的选型逻辑。

网络游戏的全部难题可以压缩成两个词:信任(谁的机器说了算)与延迟(说的话多久到)。架构设计先答信任题,同步设计再答延迟题,顺序不能反。本节按这个顺序展开。

第一决策:权威放在哪

对等架构:一个玩家当主机,其他人的机器连过来。省服务器钱、开局快,适合合作游戏与朋友局;代价是主机玩家的网络成了全队天花板,主机作弊全队遭殃。服务器权威架构:逻辑跑在独立的服务器进程上,客户端只提交意图、接收结果。防作弊、可托管、可扩展,是对抗游戏与商业运营的正解;代价是要养服务器。第三种混合形态(区域主机)介于两者之间,按场景选用。

深井矿工改成双人合作挖矿,对等结构足够——朋友之间不互相防。若日后加排行榜与对抗,再迁服务器权威不迟。架构跟着信任模型走,是第一原则。

# 对等开局:主机创建 其他人加入 func host_game(port := 7777) -> void: var peer := ENetMultiplayerPeer.new() peer.create_server(port, 4) multiplayer.multiplayer_peer = peer func join_game(ip: String, port := 7777) -> void: var peer := ENetMultiplayerPeer.new() peer.create_client(ip, port) multiplayer.multiplayer_peer = peer

远程调用:跨端执行函数

高层接口的核心抽象是远程调用——在本地调用一个函数,它在别的机器上执行。引擎用注解体系管理这件事,每个注解对应一种传播语义:

extends Node signal chat_received(text: String) # 谁调用 谁执行 谁收到 三问定注解 @rpc("any_peer", "call_local", "reliable") func send_chat(text: String) -> void: chat_received.emit(text) @rpc("authority", "remote", "unreliable_ordered") func sync_position(pos: Vector2) -> void: %Player.global_position = pos

三问框架读注解:谁能调它(任意端或仅权威端)、在哪执行(只在远端或本地也执行)、怎么送达(可靠有序或不可靠快速)。可靠通道保证到、慢一步;不可靠通道快、可能丢——聊天用可靠(丢一句都尴尬),位置同步用不可靠(下一帧就有新位置,旧位置丢了无所谓)。通道选错是网络游戏的常见病根:高频状态走了可靠通道,一个丢包引发整队排队,表现为"忽然卡一下"。

远程调用的寻址依赖两个全局约定:每个端有编号(服务器为一,客户端依次分配),每个节点有树路径。函数签名与节点路径两端必须一致——同一个场景结构、同一份脚本,是远程调用的隐含合同。这解释了为什么多人项目要严格控制动态改树:路径一变,合同作废。

状态同步:复制、插值与预测

远程调用传"动作"(我挖了一格),状态同步传"事实"(我在这个位置)。事实的同步有标准三板斧。

复制:引擎支持把节点的指定属性自动同步给所有端(谁创建、同步哪些属性可配)。省去手写同步代码,适合低频状态(血量、金币)。

插值:网络包一秒来十几二十次,画面要六十帧。远端角色的位置不能直接用(一跳一跳的),要在最近两个收到的位置之间平滑插值,多等一小段缓冲时间换平滑。这是"别人看着顺滑"的全部秘密。

预测:本地角色不等服务器确认,立刻执行预判动作;服务器结果回来若与预判不符,悄悄纠正。这是"自己操作不延迟"的全部秘密。预测实现复杂,合作游戏可以不做(等确认也无感),对抗游戏绕不开。

# 远端角色插值:缓冲一帧换平滑 var _net_pos := Vector2.ZERO var _prev_pos := Vector2.ZERO var _interp := 0.0 @rpc("any_peer", "remote", "unreliable_ordered") func net_update(pos: Vector2) -> void: _prev_pos = %Body.global_position _net_pos = pos _interp = 0.0 func _physics_process(delta: float) -> void: if is_multiplayer_authority(): return # 本地角色不插值 _interp = minf(_interp + delta * 20.0, 1.0) %Body.global_position = _prev_pos.lerp(_net_pos, _interp)

底层传输:选管道

高层接口之下,引擎提供几条传输管道,特性各异:可靠连接型(内建的网络传输库,带连接管理与通道,绝大多数游戏的选择)、轻量不可靠型(局部网络发现与简单消息)、网页兼容型(浏览器平台的网络限制需要专用通道)。选择逻辑很简单:常规联网用可靠连接型,网页平台用其兼容通道,局域网发现用轻量型。更底层还有原始套接字接口可用,但走到那一步的需求(自定义协议、与外部服务对接)已超出引擎网络的常规领地。

⚠️ 常见坑:本地测试全好,上线就"找不到房间"。九成是网络地址转换的问题——朋友之间直连需要打洞或中继,商业上线要走中继服务或干脆服务器权威架构。对等结构在家测得好,是因为你们恰好在同一局域网。立项时把"玩家怎么连上彼此"当成产品问题而不只是技术问题来回答。

联机改造的工程清单

把单机游戏改造成多人,改动是系统性的,清单比代码更有用:玩家生成改为按端号实例化且权威在各自端;游戏状态(瓦片地形、矿石库存)的修改权收归权威端,其余端只发请求;随机数改用同步种子(两端生成同样的世界);场景切换由权威端广播驱动;输入本地即时、状态远端插值。这份清单的每一项都是"信任模型"的具体化——把"谁说了算"贯彻到每个状态上,多人改造就不会漏。

图 1 一次联机挖掘的两端旅程

图 1 一次联机挖掘的两端旅程

本节要点回顾

  • 两个词概括网络:信任(权威模型)与延迟(同步策略),先答信任再答延迟
  • 架构跟着信任走:朋友局对等够用,对抗与商业运营上服务器权威
  • 注解三问:谁能调、在哪执行、怎么送达;通道选错是"偶发卡顿"的常见病根
  • 三板斧:复制管低频状态、插值救远端平滑、预测救本地手感
  • 传输管道按场景选:常规用可靠连接型、网页用兼容通道、局域网发现用轻量型
  • 联机改造清单:生成按端号、状态收权威、随机用同步种子——把信任模型贯彻到每个状态

网络让世界能装下更多人,下一节转向内部效率:插件与自动化把重复劳动变成资产。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U