You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity Netcode for GameObjects 服务器端玩家流畅移动实现问询

服务器权威玩家移动实现指南(Netcode for GameObjects)

之前尝试的问题根源

  • 直接本地修改位置:客户端修改的位置会被Network Transform(以下简称NT)的服务器同步覆盖——因为NT默认是服务器权威模式,只有服务器计算的位置会同步到所有客户端,客户端本地修改无效。
  • 每帧发ServerRpc传位移:每帧调用RPC会造成网络拥堵,加上网络延迟,客户端要等服务器响应才会更新位置,必然卡顿。哪怕改成Translate,延迟带来的手感滞后也无法解决。

正确实现核心:输入预测 + 服务器校验修正

竞技类游戏的服务器权威移动,核心是客户端本地输入预测 + 服务器权威计算+回滚修正,结合NT的同步逻辑,既能保证服务器对位置的绝对控制权,又能让客户端获得流畅的手感。

步骤1:客户端发送输入而非位移,本地预测移动

不要每帧发送位移,而是发送玩家的输入指令(比如方向向量),减少网络带宽占用;同时客户端基于输入提前预测移动,保证手感流畅。

修改后的基础代码:

using UnityEngine;
using Unity.Netcode;
using System.Collections.Generic;

public class PlayerNetwork : NetworkBehaviour
{
    [SerializeField] private float moveSpeed = 10f;
    // 客户端本地预测的位置基准
    private Vector3 predictedPos;
    // 缓存近期输入,用于后续回滚修正
    private Queue<Vector3> inputBuffer = new Queue<Vector3>();
    private const int maxBufferSize = 20;

    void Start()
    {
        if (IsOwner)
        {
            predictedPos = transform.position;
            // 监听服务器位置同步事件,用于修正预测误差
            GetComponent<NetworkTransform>().OnNetworkPositionChanged += OnServerPosUpdate;
        }
    }

    void Update()
    {
        if (!IsOwner) return;

        // 收集当前输入
        Vector3 inputDir = Vector3.zero;
        if (Input.GetKey(KeyCode.W)) inputDir.y = -1f;
        if (Input.GetKey(KeyCode.S)) inputDir.y = 1f;
        if (Input.GetKey(KeyCode.A)) inputDir.x = -1f;
        if (Input.GetKey(KeyCode.D)) inputDir.x = 1f;
        inputDir = inputDir.normalized; // 避免斜向移动速度过快

        // 缓存输入
        inputBuffer.Enqueue(inputDir);
        if (inputBuffer.Count > maxBufferSize) inputBuffer.Dequeue();

        // 客户端本地预测移动
        predictedPos += inputDir * moveSpeed * Time.deltaTime;
        transform.position = predictedPos;

        // 定期发送输入到服务器(比如每0.1秒,而非每帧)
        SendInputToServerRpc(inputDir);
    }

    [ServerRpc]
    void SendInputToServerRpc(Vector3 inputDir)
    {
        // 服务器基于输入计算权威位置
        transform.position += inputDir * moveSpeed * Time.deltaTime;
        // NT会自动将服务器位置同步到所有客户端
    }
}

步骤2:服务器位置回滚修正

客户端的预测和服务器的计算必然存在误差,需要在收到服务器同步的权威位置时,平滑修正本地位置,避免突兀的瞬移:

在上面的代码中添加修正逻辑:

private void OnServerPosUpdate(Vector3 oldPos, Vector3 newPos)
{
    if (!IsOwner) return;

    // 计算预测位置与服务器位置的误差
    float error = Vector3.Distance(predictedPos, newPos);
    if (error < 0.1f) return; // 误差过小无需修正

    // 回滚到服务器位置,重新应用缓存的输入
    predictedPos = newPos;
    foreach (var input in inputBuffer)
    {
        predictedPos += input * moveSpeed * Time.deltaTime;
    }
    // 平滑过渡到修正后的位置
    transform.position = Vector3.Lerp(transform.position, predictedPos, 10f * Time.deltaTime);
}

步骤3:优化Network Transform设置

  • 保持Authority为Server(默认值)
  • 开启Interpolation,设置Interpolation Delay为0.1秒左右(匹配输入发送间隔)
  • 保留仅同步X、Y轴的设置
  • 调整Sync Interval为0.1秒,减少不必要的网络同步

关于Client Network Transform的说明

Client Network Transform是客户端权威模式,客户端直接控制位置并同步到服务器,这种模式下极易被作弊(比如外挂修改位置),所以竞技类游戏绝对不推荐使用,必须坚持服务器权威的实现方案。

内容的提问来源于stack exchange,提问作者Maik Thiele

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 18:45:19