Menu
CoddyTech

用于物理计算的 FixedUpdate

本课属于 Coddy Unity 学习旅程的“物理与游戏玩法”单元。第 4 课,共 71 课。

Unity 会按照固定的物理步长移动刚体,每步为 0.02 秒(Time.fixedDeltaTime),每秒 50 步,不受帧率影响。每个物理步开始前,都会运行一次 FixedUpdate()。每绘制一帧,就会运行一次 Update(),每秒可能运行 30、60 或 144 次:帧率为 144 时,大多数帧都没有物理步;在运行缓慢的计算机上,一帧可能包含两个物理步。

由此可得两条规则。在 Update() 中添加的力每帧都会添加一次,因此计算机越快,推力就越大:随时间持续作用的力应放在 FixedUpdate() 中。GetKeyDown 只会在一帧中为 true;如果这一帧没有物理步,FixedUpdate() 就看不到它,按键也会被忽略。因此,要在 Update() 中读取按键,在 bool 变量中记下按键状态,再在 FixedUpdate() 中处理。下面这艘船会受到持续的风力推动,并在点击时向侧面冲刺:

private bool dashQueued;

void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        dashQueued = true;   // 记住这次点击
    }
}

void FixedUpdate()
{
    rb.AddForce(Vector3.forward * wind);   // 每一步都施加稳定的推力
    if (dashQueued)
    {
        rb.AddForce(Vector3.right * 4f, ForceMode.Impulse);
        dashQueued = false;   // 点击一次,冲刺一次
    }
}

使用后将 bool 变量清除很重要:如果它一直保持 true,船就会在每个物理步都冲刺。也可以像青蛙跳跃那样,直接在 Update() 中添加一次冲量;将 bool 变量用于记下按键状态,可以把所有推力都放在同一处,方便和相关的力一起管理。按住的按键(GetKey、GetAxis)表示一种状态,而不是某个瞬间,因此 FixedUpdate() 可以直接读取它们。在 FixedUpdate() 中,Time.deltaTime 返回每个物理步的时长 0.02 秒。

challenge icon

挑战

简单

把雪橇的两项任务放到正确的方法中。

  1. 将两个方向键的 if 代码块从 Update() 移到 FixedUpdate() 中。
  2. 添加 private bool hopPressed;。在 Update() 中,按下 Input.GetKeyDown(KeyCode.Space) 时将它设为 true。
  3. 在 FixedUpdate() 中,当 hopPressed 已设置时,添加冲量,然后将它设为 false。

按下“开始”:方向键会均匀地推动雪橇,每次按下空格键都会跳起。然后点击“检查”。

亲手试试

using UnityEngine;

public class Sled : MonoBehaviour
{
    public float push = 6f;
    public float hop = 5f;
    private Rigidbody rb;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        if (Input.GetKey(KeyCode.RightArrow))
        {
            rb.AddForce(Vector3.right * push);
        }
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            rb.AddForce(Vector3.left * push);
        }
    }

    void FixedUpdate()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            rb.AddForce(Vector3.up * hop, ForceMode.Impulse);
        }
    }
}

物理与游戏玩法中的所有课

自己练习: Unity 在线编辑器