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

Unity本地多人游戏:如何单独控制对象的Update()执行频率

控制单个GameObject的Update执行频率(替代全局Time.timeScale)

针对本地多人模式下需要单独控制对象时间流速的需求,以下是几个实用方案,完全避开全局Time.timeScale的影响:

方案1:自定义时间缩放变量+累积时间触发逻辑

核心思路是用不受全局时间缩放影响的Time.unscaledDeltaTime,结合自定义的localTimeScale计算累积时间,达到阈值后执行目标逻辑。每个对象可以独立调整缩放比例,完全不影响其他对象。

示例代码:

public class LocalScaledUpdate : MonoBehaviour
{
    // 单个对象的时间缩放比例,1为正常速度,0.5为慢动作,2为加速
    public float localTimeScale = 1f;
    private float accumulatedTime = 0f;
    // 固定时间步长,和Unity默认的fixedDeltaTime保持一致即可
    private readonly float fixedStep = 0.02f;

    void Update()
    {
        // 累加不受全局timeScale影响的时间,并按本地缩放比例计算
        accumulatedTime += Time.unscaledDeltaTime * localTimeScale;

        // 当累积时间达到固定步长时,执行逻辑(支持多帧累积的情况)
        while (accumulatedTime >= fixedStep)
        {
            RunScaledLogic();
            accumulatedTime -= fixedStep;
        }
    }

    // 把原本放在Update里的逻辑移到这里
    private void RunScaledLogic()
    {
        // 示例:移动逻辑
        transform.Translate(Vector3.forward * 0.1f);
        // 其他需要缩放的逻辑(比如状态判断、动画参数更新等)
    }
}

方案2:协程驱动的定时逻辑执行

如果你的逻辑不需要每帧都检测,可以用协程结合WaitForSecondsRealtime(不受全局时间缩放影响)来控制执行间隔,调整localTimeScale后间隔会自动变化,还能随时暂停/重启。

示例代码:

public class CoroutineScaledUpdate : MonoBehaviour
{
    public float localTimeScale = 1f;
    private Coroutine _scaledUpdateCoroutine;

    void OnEnable()
    {
        // 开启协程
        _scaledUpdateCoroutine = StartCoroutine(ScaledUpdateLoop());
    }

    void OnDisable()
    {
        // 关闭协程,避免内存泄漏
        if (_scaledUpdateCoroutine != null)
            StopCoroutine(_scaledUpdateCoroutine);
    }

    private IEnumerator ScaledUpdateLoop()
    {
        while (true)
        {
            // 计算缩放后的等待时间:固定步长 / 本地时间缩放比例
            float waitTime = 0.02f / localTimeScale;
            // 使用不受全局timeScale影响的等待方法
            yield return new WaitForSecondsRealtime(waitTime);
            
            // 执行缩放后的逻辑
            RunScaledLogic();
        }
    }

    private void RunScaledLogic()
    {
        // 你的业务逻辑代码
    }
}

方案3:单独处理动画与物理组件

如果对象包含Animator或Rigidbody,需要额外单独调整:

  • 动画:直接设置animator.speed = localTimeScale,可以独立控制动画播放速度,不受全局Time.timeScale影响。
  • 物理:关闭Rigidbody的自动物理更新(设为isKinematic = true),然后用自定义的时间缩放逻辑计算位移、速度等物理量,替代Unity的自动物理模拟。

示例物理控制代码:

public class LocalScaledPhysics : MonoBehaviour
{
    public float localTimeScale = 1f;
    private Rigidbody _rb;
    private float _accumulatedPhysicsTime = 0f;
    private readonly float _fixedStep = 0.02f;

    void Awake()
    {
        _rb = GetComponent<Rigidbody>();
        // 关闭自动物理,改用自定义逻辑
        _rb.isKinematic = true;
    }

    void Update()
    {
        _accumulatedPhysicsTime += Time.unscaledDeltaTime * localTimeScale;

        while (_accumulatedPhysicsTime >= _fixedStep)
        {
            // 自定义物理更新:比如根据速度更新位置
            transform.position += _rb.velocity * _fixedStep;
            // 可以在这里添加力的计算、碰撞检测等逻辑
            _accumulatedPhysicsTime -= _fixedStep;
        }
    }
}

为什么你之前的方法无效?

Time.timeScale是全局生效的,且Unity的Update执行频率本身就受它影响——当你在某个Update函数里修改Time.timeScale,同一帧内其他对象的Update已经按照修改前的时间缩放执行了;而且单线程下,你修改后立刻重置,其他对象根本没机会受到这个临时修改的影响,所以完全起不到单独控制的作用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 08:13:16