UpdateメソッドとFixedUpdateメソッドの使い分け【Unity】

Unityスクリプトには定期的に呼ばれるメソッドとしてUpdateメソッドとFixedUpdateメソッドがあります。それぞれどのように使い分ければよいのでしょうか?

UpdateメソッドとFixedUpdateメソッドの違い

両方ともに定期的に呼び出されるメソッドですが、以下のような違いがあります。

  • Updateメソッド:1フレームごとに呼び出されるメソッド(端末の描画速度によって呼び出される回数が異なる)
  • FixedUpdateメソッド:一定時間ごとに呼び出されるメソッド(端末に依存せずに再現性がある)

なお、FixedUpdateメソッドの呼び出されるタイミングは「Edit」→「Project Settings」→「Time」のFixed Timestepで設定でき、デフォルトでは0.02秒間隔(30fps)となっています。

Updateメソッドを使う例

UpdateメソッドはUIの入力処理(ボタンを押す、キー入力をするなど)に用います。一定間隔ごとに呼び出されるFixedUpdateメソッドでは、呼び出しのタイミングによっては入力処理が検知できなくなってしまう可能性があるので、Updateメソッドの方が確実に入力処理を検知できて望ましいです。

FixedUpdateメソッドを使う例

FixedUpdateメソッドを使う代表的な例は物理演算を行うときです。

Updateメソッドに物理演算を書いてしまうと、端末の描画速度によりUpdateメソッドが呼ばれるタイミングにむらができてしまうので、物体の移動がカクカクになったり物理演算の結果に再現性が保てなくなってしまう可能性があります。

一方、FixedUpdateメソッドはUpdateメソッドがフレーム落ちしていても、独立して一定時間ごとに呼び出されるので、物理演算の結果再現性が保てるようになります。

同じ処理をUpdateメソッドとFixedUpdateメソッドで実行してみると…

では、同じ物理演算の処理をUpdateメソッドとFixedUpdateメソッドに書いたらどのような違いが出るでしょうか。赤と青の立方体を用意して、赤はUpdateメソッドで、青はFixedUpdateメソッドで同じように力を加えてみましょう。

同じ処理を、赤い立方体はUpdateメソッドに、青い立方体はFixedUpdateメソッドに記述しています。
なお、このプログラミングのソースコードは下に示しています。

これを実行してみると、赤と青の立方体で動きが大きく異なってしまいます。さらに、同じプログラムを別のパソコンで実行してみると、環境によっては赤い立方体も転がらなくなってしまいます。一方、青い立方体はどの環境で実行しても同じような挙動を示します。

このようにFixedUpdateメソッドで呼び出す間隔を一定にすれば再現性を持てますが、Updateメソッドではフレームの間隔が環境の違いやFPSの違いによって異なってしまうので、環境によって物理演算の結果が全く違うものになってしまうことが分かります。

UpdateメソッドとFixedUpdateメソッドの使い方

ともにUnityスクリプトのメッセージシステムというという機能で動作しています。

C#スクリプトを最初に作成するとUpdateメソッドはあらかじめ作成された状態になっているので、それを利用してUpdateメソッドを記述していきましょう。

また、FixedUpdateという名前のメソッドを作成すると自動的にメッセージシステムに組み込まれて、一定間隔で実行されるメソッドが出来上がります。(MonoBehaviour継承クラスである必要はあります)

それでは、先ほどお示しした物理演算をUpdateメソッドとFixedUpdateメソッドに記述する例を見てみましょう。立方体が落ちないように土台を作ってから、以下のスクリプトを空(カラ)のGameObjectにアタッチしてみてください。(もちろん、物理演算をUpdateメソッドに記述するのは誤った使い方なので、練習用以外ではマネしないでくださいね)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
  
public class Manager : MonoBehaviour
{
    Rigidbody rigidbody1;
    Rigidbody rigidbody2;
 
    // Start is called before the first frame update
    void Start()
    {
        GameObject obj1 = GameObject.CreatePrimitive(PrimitiveType.Cube);
        obj1.name = "Cube1";
        obj1.transform.position = new Vector3(-1, 3, 1);  //赤いCubeの座標を指定する
        obj1.transform.rotation = Quaternion.Euler(10, 0, 0);   //赤いCubeの回転を指定する
        obj1.GetComponent<Renderer>().material.color = Color.red;  //赤いCubeの色を指定する
        rigidbody1 = obj1.AddComponent<Rigidbody>();  //Rigidbodyをアタッチする

        GameObject obj2 = GameObject.CreatePrimitive(PrimitiveType.Cube);
        obj2.name = "Cube2";
        obj2.transform.position = new Vector3(-1, 3, -1);  //青いCubeの座標を指定する
        obj2.transform.rotation = Quaternion.Euler(10, 0, 0);   //青いCubeの回転を指定する
        obj2.GetComponent<Renderer>().material.color = Color.blue;  //青いCubeの色を指定する
        rigidbody2 = obj2.AddComponent<Rigidbody>();  //Rigidbodyをアタッチする
    }
  
    // Update is called once per frame
    void Update()
    {
         rigidbody1.AddForce(1,0,0);  //力を加える
    }
    void FixedUpdate()
    {
         rigidbody2.AddForce(1,0,0);  //力を加える
    }
}

これを実行すると先ほどのような結果になります。なお、赤い立方体の挙動は環境によって全く違うものになるので、自分の環境で再現してみる場合は、AddForce(1,0,0)のパラメーターを変えていろいろ試してみてください。

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)