代码之家  ›  专栏  ›  技术社区  ›  Olivier Pons

帧速率无关fixedupdate vs update

  •  1
  • Olivier Pons  · 技术社区  · 6 年前

    我已经读过了 this 以及官方文件: fixedUpdate() deep explanation .

    所以我试着分离我的代码。首先,在 Update() ,我没有给出完整的代码变量是不言而喻的:

    private void Update()
    {
        if (Input.GetButton("Jump")) {
            if (groundsTouched>0) {
                _jumpRequest = true;
            } else {
                _keepOnJumping = true;
            }
        } else {
            _keepOnJumping = false;
        }
        /* Handle release button: */
        _fallRequest = true;
    }
    

    现在我在做所有的计算 FixedUpdate() 这样地:

    private void FixedUpdate()
    {
        if (_jumpRequest) {
            if (!_jumpGravitySent) {
                _jumpGravitySent = true;
                _animator.SetBool("Jump", true);
                _jumpRequest = false;
                jumpTimeCounter = jumpTime;
                /* Cancel all force (couldn't find a better way) */
                _rigidbody.velocity = Vector3.zero;
                _rigidbody.angularVelocity = Vector3.zero;
                _rigidbody.AddForce(
                    Vector3.up * jumpVelocity, ForceMode.VelocityChange
                );
            }
        } else if (_keepOnJumping) {
            jumpTimeCounter -= Time.fixedDeltaTime;
            if (jumpTimeCounter >= 0) {
                _rigidbody.AddForce(
                    Vector3.up * jumpVelocity * jumpKeepMultiplier, 
                    ForceMode.Acceleration
                );
            }
        }
        if (groundsTouched == 0 && 
            _rigidbody.velocity.y > velocityFallMin &&
            _rigidbody.velocity.y < velocityFallMax
        ) {
            _animator.SetBool("Jump", false);
            _animator.SetBool("Fall", true);
        }
        if (_fallRequest) {
            _fallRequest = false;
            _jumpGravitySent = false;
            _keepOnJumping = false;
        }
    }
    

    我遇到的问题真的很奇怪:当fps很低时,玩家不能跳得很高。

    Unity QA看到了我的问题,他们的答案是:

    你所加的力取决于 您的可用性能(或帧速率本质上)。

    如果转到“编辑”->“项目设置”->“时间”并将“固定时间步长”更改为 值越大,您将得到预期的行为。尝试一些 固定时间步长的不同值,并查看行为如何更改。

    另一个建议是重写代码,使其不依赖于 帧速率(例如,使用速度而不是强制或添加特定量 不依赖于时间步)。

    “另一个建议是重写代码,使其不依赖于帧速率”->您将如何做到这一点,我认为我的代码上面正在做!

    我错过了什么?我做错了什么/有什么办法?

    0 回复  |  直到 6 年前
        1
  •  1
  •   Galandil    6 年前

    我想知道是谁给了你这个答案,这是卑鄙的。

    让我解释一下发生了什么, 现实中 .

    1)首先 fixedDeltaTime : 此值从不依赖于帧速率 . 它可以在编辑器中设置(在 Edit->Project Settings->Time ,这是运行时保存的值, 除非 任何脚本都会使用赋值来更改它。统一引擎永远不会自行改变它。

    2)物理循环:在一个完整的引擎循环中,unity将执行多个物理循环(0、1或更多),然后执行一个渲染循环。每个渲染循环执行的物理循环数基于此 固定三角体 以及从上一次(即 deltaTime 渲染循环的)。

    例如,假设 fixedDeltaTime = 0.0166667 从上一个物理循环开始的时间就不那么长了 10 Unity女士不会执行物理循环。现在假设下一帧已经在 这意味着自从上次物理循环以来, 20 女士通过了。因为这比 固定三角体 ,unity将执行一个物理循环。 有时可能会出现帧渲染非常慢(由于不可预见的原因),例如 40 女士为了保持物理模拟的一致性,Unity必须运行 物理循环,因为 0.04/0.0166667 = 2.4 .

    请记住,unity会跟踪上一个物理循环开始时间和下一个物理循环开始时间之间的差异:如果渲染持续 ms每帧,和 固定三角体 设置为 166667 ms(60hz),一旦启动运行时,unity将执行第一个物理循环,然后在第一个渲染帧之后跳过一个(因为 MS已通过,而不是 十六万六千六百六十七 ,然后在第二个渲染帧之后执行一个物理循环( 二十 MS通过了反对 十六万六千六百六十七 )但是现在我们的回路被 3.3333 女士,所以Unity会跟踪的。

    在第三帧之后,另一帧 ms已通过,但此后将不会执行任何物理循环 10+3.3333 = 13.3333 仍然低于 固定三角体 . 现在,假设第四个渲染帧“出错”,它将持续 25 ms而不是仅仅 . 在下一个物理循环开始时,总共 25+13.3333 = 38.3333 自上次物理更新以来已经通过,并且 38.3333/16.6667 = 2.3 ,统一将执行 在渲染第5帧之前,连续物理循环以跟上固定步长的模拟。


    在所有这些介绍之后,让我们回到你的问题,看看会发生什么:

    在某一点上你执行 Update() 并设置 _jumpRequest = true; _fallRequest = true; .

    在这个渲染帧之后, FixedUpdate() 是第一次执行,执行 AddForce ForceMode.VelocityChange 线条和设置 _fallRequest = false; , _jumpGravitySent = false; _keepOnJumping = false; . 结束后 修正更新() ,Unity执行物理模拟,通过物理引擎调整刚体的位置和速度。

    现在问题触发了:由于渲染帧很慢,物理循环至少连续执行两次,但是没有 UpDead() 在两者之间执行,所以 修正更新() 跳过,但物理模拟第二次运行,将刚体位置相对于预期的最上面位置向下拖动。

    什么时候? UpDead() 再次执行,最后是您的代码集 _keepOnJumping = true; ,当它回到 修正更新() 它将执行 AddForce ForceMode.Acceleration ,但紧接着,第二次执行另一个物理模拟(由于低帧速率),再次向下拖动刚体,然后才能在屏幕上进行渲染。

    希望这有助于理解您的问题以及问题发生的原因,以便您现在有正确的工具来正确地解决它。