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

Photon Fusion物体位置同步问题及脚本代码疑问

Photon Fusion 玩家推箱子同步问题解决方案

问题描述

我基于Photon Fusion框架编写了一段实现玩家推动箱子功能的C#脚本,脚本如下:

public class PlayerTrigger : NetworkBehaviour
{
    [SerializeField] NetworkCharacterControllerPrototype characterControllerPrototype;
    [SerializeField] NetworkTransform _root;
    [SerializeField] private float pushPower = 2.0f; // 推动箱子的力量
    NetworkRigidbody _rootBox;
    bool _isTele = false;
    bool _isPushBox = false;
    Rigidbody _pushedBody;
    [Networked]
    public Vector3 PushDirection { get; set; }

    public override void FixedUpdateNetwork()
    {
        base.FixedUpdateNetwork();

        if (_isPushBox && _pushedBody != null)
        {
            _pushedBody.velocity = PushDirection * pushPower;
            _isPushBox = false;
            _rootBox.FixedUpdateNetwork();
        }
    }

    private void OnControllerColliderHit(ControllerColliderHit hit)
    {
        if (hit.gameObject.tag == "MoveBox")
        {
            _pushedBody = hit.collider.attachedRigidbody;
            _rootBox = hit.gameObject.GetComponent<NetworkRigidbody>();
            // 箱子没有Rigidbody或者是Kinematic状态则忽略
            if (_pushedBody == null || _pushedBody.isKinematic)
            {
                return;
            }
            // 计算推动方向
            PushDirection = new Vector3(hit.moveDirection.x, 0, hit.moveDirection.z);
            _isPushBox = true; // 设置需要施加力量的标记
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("TeleBox"))
        {
            _isTele = true;
        }
    }
}

目前箱子可被玩家推动,但不同客户端之间位置不同步,请问正确的位置同步方式是什么?另外,代码中的base.FixedUpdateNetwork()是否需要保留?


解决方案

一、解决箱子位置不同步的核心调整

当前同步问题的根源是物理操作没有遵循Fusion的网络逻辑规范,按以下几点修改即可解决:

  1. 正确配置箱子的NetworkRigidbody

    • 确保箱子对象已添加NetworkRigidbody组件,Inspector中设置:
      • 同步模式选择Predicted(适合需要即时反馈的可交互物理对象)或Interpolated
      • 勾选Sync Velocity和Sync Angular Velocity,让Fusion同步物理状态到所有客户端
    • 箱子的Rigidbody必须设置为非Kinematic,碰撞体参数(比如材质、大小)要确保和玩家控制器的碰撞交互正常
  2. 限制推动逻辑仅在Owner客户端执行
    Fusion中网络对象的状态修改必须由拥有权限的客户端(即玩家的Owner端)发起,避免多客户端同时操作导致冲突。修改逻辑如下:

    // 新增私有变量存储推动方向,无需同步
    private Vector3 _pushDirection;
    
    private void OnControllerColliderHit(ControllerColliderHit hit)
    {
        // 只有当前玩家拥有状态权限时才处理推动
        if (!HasStateAuthority) return;
    
        if (hit.gameObject.CompareTag("MoveBox"))
        {
            _pushedBody = hit.collider.attachedRigidbody;
            _rootBox = hit.gameObject.GetComponent<NetworkRigidbody>();
            
            if (_pushedBody == null || _pushedBody.isKinematic || _rootBox == null)
            {
                return;
            }
            
            _pushDirection = new Vector3(hit.moveDirection.x, 0, hit.moveDirection.z);
            _isPushBox = true;
        }
    }
    
    public override void FixedUpdateNetwork()
    {
        base.FixedUpdateNetwork();
    
        if (!HasStateAuthority) return;
    
        if (_isPushBox && _rootBox != null)
        {
            // 使用NetworkRigidbody的AddForce而非直接修改velocity
            _rootBox.Rigidbody.AddForce(_pushDirection * pushPower, ForceMode.Impulse);
            _isPushBox = false;
            // 不要手动调用_rootBox.FixedUpdateNetwork(),Fusion会自动处理物理帧同步
        }
    }
    

    关键改动:

    • 用HasStateAuthority校验权限,确保只有Owner端发起推动
    • 替换直接修改velocity为AddForce,让Fusion能正确捕获物理状态变化并同步
    • 移除PushDirection的[Networked]标记,改为普通私有变量——推动方向无需跨客户端同步,Owner端计算即可
  3. 确保玩家控制器的Network配置正确
    玩家的NetworkCharacterControllerPrototype要正确设置状态权限,确保玩家能在Owner端正常触发OnControllerColliderHit事件。

二、关于base.FixedUpdateNetwork()的保留问题

必须保留。NetworkBehaviour的基类FixedUpdateNetwork()包含了Fusion核心的网络状态同步、预测修正等逻辑,如果移除会导致当前组件的网络功能完全失效,比如玩家状态无法同步、物理预测出错等。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 21:13:18