在 Unity 游戏引擎中,“Maximum Allowed Timestep”(最大允许时间步长)是一个与物理模拟和时间管理相关的重要设置。它位于 Time Manager 中(可以通过 Edit > Project Settings > Time 访问),用于控制物理引擎在任何一帧中可以执行的物理更新的最大时间跨度。这个设置的主要目的是在帧时间波动(如游戏卡顿)时,限制物理更新的数量,从而平衡物理模拟的稳定性和游戏性能。

位置:Edit > Project Settings > Time > Maximum Allowed Timestep
默认值:0.33333 (1/3秒)
单位:秒

1. 背景知识:Unity 的时间与物理模拟

Unity 的物理引擎(如刚体动力学、碰撞检测等)依赖固定的时间步长来进行模拟,以确保物理行为在不同帧率和硬件条件下保持一致性和稳定性。以下是两个关键概念:

  • Fixed Timestep(固定时间步长)
    • 定义:物理引擎每次更新的时间间隔,默认值为 0.02 秒(即每秒 50 次更新)。
    • 作用:物理更新在脚本的 FixedUpdate() 方法中执行,每次调用对应一次物理计算。
    • 获取方式:通过 Time.fixedDeltaTime 可以访问该值。
  • Delta Time(帧时间)
    • 定义:每帧之间的实际时间间隔,由 Time.deltaTime 表示。
    • 特点:受硬件性能、游戏负载等影响,可能会有波动。例如,帧率 60 FPS 时,delta time 约为 0.0167 秒;帧率降低时,delta time 会变大。

Unity 的物理引擎会根据 delta time 和 Fixed Timestep 的关系,决定在一帧内执行多少次物理更新。


2. Maximum Allowed Timestep 的作用

当游戏运行时,如果一帧的 delta time 超过 Fixed Timestep,Unity 会尝试在该帧内执行多次物理更新,以“赶上”时间流逝。例如:

  • Fixed Timestep = 0.02 秒
  • 如果一帧的 delta time = 0.06 秒,Unity 会执行 3 次物理更新(0.06 / 0.02 = 3)。
单帧最大物理步骤数 = Maximum Allowed Timestep ÷ Fixed Timestep

但在极端情况下(例如游戏卡顿导致一帧耗时 0.5 秒),Unity 可能需要执行大量物理更新(0.5 / 0.02 = 25 次)。这会带来以下问题:

  • 性能下降:执行过多物理更新会增加 CPU 负担,可能加剧卡顿。
  • 模拟不稳定:过多的物理更新可能导致物理计算出现误差或不稳定的行为。

为了避免这些问题,Unity 引入了 Maximum Allowed Timestep,用于限制单帧内物理更新的最大时间跨度。


3. Maximum Allowed Timestep 的工作原理

  • 定义:Maximum Allowed Timestep 是 Unity 在任何一帧中允许物理引擎执行的物理更新的最大累积时间。
  • 默认值:通常为 0.3333333 秒(约 1/3 秒),但可以在 Time Manager 中调整。
  • 工作机制
    • 如果一帧的 delta time ≤ Maximum Allowed Timestep,Unity 会根据 delta time 执行相应次数的物理更新(次数 = delta time / Fixed Timestep)。
    • 如果一帧的 delta time > Maximum Allowed Timestep,Unity 只执行相当于 Maximum Allowed Timestep 的物理更新,剩余的时间推迟到下一帧。
示例

假设:

  • Fixed Timestep = 0.02 秒
  • Maximum Allowed Timestep = 0.1 秒

场景 1:一帧的 delta time = 0.06 秒

  • 0.06 < 0.1,Unity 执行 3 次物理更新(0.06 / 0.02 = 3)。

场景 2:一帧的 delta time = 0.15 秒

  • 0.15 > 0.1,Unity 只执行 5 次物理更新(0.1 / 0.02 = 5),而不是 7.5 次(0.15 / 0.02 = 7.5)。
  • 剩余的 0.05 秒(0.15 - 0.1)将推迟到下一帧处理。

通过这种方式,Maximum Allowed Timestep 限制了单帧内物理更新的数量,避免了性能问题和模拟不稳定。


4. 调整 Maximum Allowed Timestep 的影响

Maximum Allowed Timestep 的值需要根据游戏需求进行调整,不同的设置会产生不同的效果:

设置过小

  • 优点:限制物理更新次数,有助于在低帧率时保持性能。
  • 缺点:物理模拟可能无法跟上实际时间流逝,导致物体移动不连续或“跳帧”。例如,如果设置为 0.05 秒,而一帧耗时 0.1 秒,物理更新只覆盖 0.05 秒,剩余时间被忽略,可能导致物理行为不自然。
// 示例:设置过小的Maximum Allowed Timestep
Time.maximumAllowedTimestep = 0.05f; // 50ms,较小

设置过小的负面影响:

  • 物理世界变"慢动作":帧率下降时物理世界无法正常追赶
  • 延迟累积:物理模拟与实时世界可能产生越来越大的延迟
  • 玩家输入滞后:物理控制的角色对输入响应越来越滞后

设置过大

  • 优点:物理模拟更接近实际时间流逝,适合需要高精度物理的游戏。
  • 缺点:在帧时间过长时,物理引擎执行过多更新,可能导致性能下降,尤其在低端设备上。
// 示例:设置过大的Maximum Allowed Timestep
Time.maximumAllowedTimestep = 1.0f; // 1秒,过大

设置过大的负面影响:

  • 物理不稳定:大量连续的物理步骤可能导致数值不稳定
  • "螺旋死亡"风险:长时间的物理计算导致下一帧更慢,形成恶性循环
  • 玩家体验突变:物理对象在卡顿后可能"跳跃"到不合理位置
  • 穿透碰撞:高速移动物体在大步长下可能穿过薄壁碰撞器

因此,开发者需要根据游戏类型、物理复杂度以及目标平台的性能,合理权衡这个值。


5. 使用场景

  • 高性能需求(如移动游戏)
    • 建议减小 Maximum Allowed Timestep(例如 0.1 秒),以限制物理更新次数,避免低帧率时的性能瓶颈。
  • 物理精度要求高(如模拟类游戏)
    • 可以适当增大 Maximum Allowed Timestep(例如 0.5 秒),确保物理模拟尽量跟上时间流逝。
  • 动态调整
    • 在某些情况下,可以通过脚本动态调整 Time.maximumDeltaTime(对应 Maximum Allowed Timestep),根据运行时性能优化物理更新。

6. 在 Unity 中的设置

  • 位置:Edit > Project Settings > Time > Maximum Allowed Timestep
  • 脚本访问:通过 Time.maximumDeltaTime 属性可以读取或修改该值。例如:
    Time.maximumDeltaTime = 0.1f; // 设置为 0.1 秒

7. 常见问题与解决方案

1. 场景切换时物理对象闪烁或跳跃

问题:场景加载导致大幅帧率下降,物理对象位置突变

解决方案:场景切换时临时冻结物理

// 问题:场景加载导致大幅帧率下降,物理对象位置突变
// 解决方案:场景切换时临时冻结物理

void PrepareSceneTransition()
{
    // 保存原始设置
    float originalFixedDeltaTime = Time.fixedDeltaTime;
    float originalMaximumAllowedTimestep = Time.maximumAllowedTimestep;
    
    // 暂停物理(极小的fixedDeltaTime实际上停止了物理模拟)
    Time.fixedDeltaTime = 0.0001f;
    Time.maximumAllowedTimestep = 0.0001f;
    
    StartCoroutine(LoadSceneAndRestorePhysics(originalFixedDeltaTime, originalMaximumAllowedTimestep));
}

IEnumerator LoadSceneAndRestorePhysics(float originalFixed, float originalMax)
{
    // 执行场景加载
    AsyncOperation operation = SceneManager.LoadSceneAsync("NewScene");
    yield return operation;
    
    // 恢复物理并等待几帧使物理稳定
    Time.fixedDeltaTime = originalFixed;
    Time.maximumAllowedTimestep = originalMax;
    
    // 等待物理稳定
    for (int i = 0; i < 5; i++)
    {
        yield return new WaitForFixedUpdate();
    }
}

2. 快速移动物体穿墙问题

问题:当游戏帧率下降,快速物体可能穿过薄墙

解决方案:结合ContinuousSpeculative碰撞检测和合理的Maximum Allowed Timestep

// 问题:当游戏帧率下降,快速物体可能穿过薄墙
// 解决方案:结合ContinuousSpeculative碰撞检测和合理的Maximum Allowed Timestep

void ConfigureHighSpeedObject()
{
    // 对快速物体使用连续碰撞检测
    Rigidbody rb = GetComponent<Rigidbody>();
    rb.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
    
    // 设置更保守的时间步长
    if (Time.maximumAllowedTimestep > 0.2f)
    {
        Time.maximumAllowedTimestep = 0.2f;
    }
    
    // 如果你只需要为此物体调整碰撞行为,不要更改全局的Time设置
}

3. 螺旋死亡问题

问题:物理计算耗时→导致更多积累的时间→导致更多物理计算→更长耗时→...
解决方案:实施应急物理简化机制

// 问题:物理计算耗时→导致更多积累的时间→导致更多物理计算→更长耗时→...
// 解决方案:实施应急物理简化机制
public class PhysicsEmergencyHandler : MonoBehaviour
{
    private float _normalFixedDeltaTime;
    private float _normalMaximumAllowedTimestep;
    private int _lowFpsFrameCount = 0;
   
    void Start()
    {
        _normalFixedDeltaTime = Time.fixedDeltaTime;
        _normalMaximumAllowedTimestep = Time.maximumAllowedTimestep;
    }
   
    void Update()
    {
        float currentFPS = 1.0f / Time.deltaTime;

        if (currentFPS < 15)
        {
            _lowFpsFrameCount++;
            
            // 连续5帧低于15fps,启动应急措施
            if (_lowFpsFrameCount >= 5)
            {
                EnableEmergencyPhysicsMode();
            }
        }
        else
        {
            _lowFpsFrameCount = 0;
            
            // 帧率恢复,且已经处于应急模式,恢复正常设置
            if (Time.fixedDeltaTime > _normalFixedDeltaTime * 1.5f)
            {
                RestoreNormalPhysicsMode();
            }
        }
    }
    
    void EnableEmergencyPhysicsMode()
    {
        // 降低物理精度以恢复性能
        Time.fixedDeltaTime = 0.04f; // 降至25Hz
        Time.maximumAllowedTimestep = 0.1f; // 限制追赶
        
        // 可以临时简化物理计算
        Physics.defaultSolverIterations = 2; // 降低精度
        
        Debug.LogWarning("已启用物理应急模式");
    }
   
    void RestoreNormalPhysicsMode()
    {
        Time.fixedDeltaTime = _normalFixedDeltaTime;
        Time.maximumAllowedTimestep = _normalMaximumAllowedTimestep;
        Physics.defaultSolverIterations = 6; // 恢复默认值
        
        Debug.Log("已恢复正常物理模式");
    }
}

8. 总结

Unity 的 “Maximum Allowed Timestep” 是一个用于限制物理引擎在单帧内执行物理更新最大时间跨度的设置。它的核心作用是:

  • 防止性能问题:避免在帧时间过长时执行过多物理更新。
  • 保持模拟稳定性:限制更新次数,减少极端情况下的物理计算误差。

开发者应根据游戏的具体需求(如物理精度、性能要求)和目标平台,合理调整该值,以在物理模拟的连续性和游戏性能之间找到平衡点。

Logo

分享前沿Unity技术干货和开发经验,精彩的Unity活动和社区相关信息

更多推荐