Menu
CoddyTech

物理演算のためのFixedUpdate

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

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つの役割を、適切なメソッドに配置しましょう。

  1. 矢印キーの2つの if ブロックを Update() から FixedUpdate() に移動します。
  2. private bool hopPressed; を追加します。Update() で、Input.GetKeyDown(KeyCode.Space) のときに true を設定します。
  3. FixedUpdate() で、hopPressed が設定されているときにインパルスを加え、その後 false に設定します。

「プレイ」を押します。矢印キーで均等に押し進み、Spaceキーを押すたびに跳びます。その後、「確認」を押します。

自分で試してみよう

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プレイグラウンド