Menu
CoddyTech

物理演算のためのFixedUpdate

CoddyのUnityジャーニー「物理演算とゲームプレイ」セクションの一部。レッスン 4/63。

Unityは、フレームレートにかかわらず、0.02秒間隔の固定物理ステップ(Time.fixedDeltaTime)で、1秒あたり50回、剛体を動かします。FixedUpdate()は各ステップの直前に実行されます。Update()は描画されたフレームごとに1回実行され、1秒あたり30回、60回、または144回実行されることがあります。144回の場合、ほとんどのフレームでは物理ステップがまったく発生せず、低速なコンピューターでは1つのフレーム内に2回発生することもあります。

ここから2つのルールが導かれます。Update()で力を加えるとフレームごとに1回加わるため、コンピューターが速いほど強く押されます。時間をかけて作用する力はFixedUpdate()に記述します。また、GetKeyDownがtrueになるのは1フレームだけです。そのフレームに物理ステップがなければ、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;   // 1クリックにつき1回ダッシュ
    }
}

使ったあとにboolをクリアすることが重要です。trueのままにすると、毎ステップダッシュしてしまいます。カエルのジャンプのように、単一のインパルスをUpdate()から直接加えることもできます。boolを使えば、すべての押す力を、それが作用する力のそばにまとめて記述できます。押し続けるキー(GetKey、GetAxis)は瞬間ではなく状態を表すため、FixedUpdate()から直接読み取れます。FixedUpdate()内では、Time.deltaTimeはステップの時間である0.02を返します。

challenge icon

チャレンジ

簡単

凍った湖のそりは、2つの処理がどちらも間違ったメソッドにあります。矢印キーによる推進処理がUpdate()内にあるため、コンピューターの速度が速いほど強く押されます。スペースキーによるインパルスでのジャンプ処理がFixedUpdate()内にあるため、キーを押しても反応しないことがあります。

  • 矢印キーによる推進処理をFixedUpdate()に移します。
  • Update()でスペースキーの入力を読み取り、hopPressedという名前のboolに保存します。FixedUpdate()では、それがセットされているときにジャンプし、その後クリアします。

Playを押して両方を試し、次にCheckを押します。

自分で試してみよう

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);
        }
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

物理演算とゲームプレイのすべてのレッスン