こんにちわ、Unityエンジニアのオオバです。

Unityの更新関数は3つあります。

それぞれ役割と意味があるのですが、今回はUpdate関数LateUpdate関数でハマってしまいました。そのエピソードを元にした記事です。


Update関数でオブジェクトを動かすことは、よく見かける処理の1つだと思います。

Update関数でUnity-chanを平行移動させる
====

下記のUpdateTest.csを動かすGameObject(今回の場合Unity-chan)にAddComponentして再生します。

【UpdateTest.cs】

using UnityEngine;  
using System.Collections;  

public class UpdateTest : MonoBehaviour  
{
    void Update ()  
    {
        // Unity-chanが毎フレーム2cm移動する  
        transform.Translate(new Vector3(0.02f, 0));  
    }
}

UnityのUpdate関数とLateUpdate関数の狭間でハマる_49

このようにUnity-chanが毎フレームX軸方向に2cm平行移動するようになりました。

Unity-chanをカメラで追いかけてみる
====

Unity-chanが動いているだけでしたが、その動きをカメラで追いかけてみます。

下記のChaseUnityChanCamera.csをカメラにAddComponentして、下図のようにUnity Chanの参照を渡して再生します。

UnityのUpdate関数とLateUpdate関数の狭間でハマる_62

【ChaseUnityChanCamera.cs】

using UnityEngine;  
using System.Collections;  

public class ChaseUnityChanCamera : MonoBehaviour  
{
    public Transform unityChan;  

    void Update ()  
    {
        var pos = unityChan.position;  
        pos.y = 0.7f;  
        // Unity-chanの方をマイフレーム向くようにする  
        transform.LookAt(pos);  
    }
}

UnityのUpdate関数とLateUpdate関数の狭間でハマる_85

すると、このようにUnity-chanの方を毎フレームカメラ向くようになりました。

ここからが本題で、このままでは不完全です。

  1. 【1フレーム目】
    1. UpdateTest Update処理 (Unity-chan移動処理)
    2. ChaseUnityChanCamera Update処理 (カメラがUnity-chanを追いかける処理)
  2. 【2フレーム目】
    1. UpdateTest Update処理 (Unity-chan移動処理)
    2. ChaseUnityChanCamera Update処理 (カメラがUnity-chanを追いかける処理)

という決まった順番で実行されれば、特に問題は起きません。

しかし、、、

実際はUpdate関数の順番というのは保証されていません。

実際のUpdate関数同士の処理順番
====

  1. 【1フレーム目】
    1. UpdateTest Update処理 (Unity-chan移動処理)
    2. ChaseUnityChanCamera Update処理 (カメラがUnity-chanを追いかける処理)
  2. 【2フレーム目】
    1. ChaseUnityChanCamera Update処理 (カメラがUnity-chanを追いかける処理)
    2. UpdateTest Update処理 (Unity-chan移動処理)

これがどのような問題になるかというと、今回のサンプルでは、移動距離が少なかったため気になりませんが、移動距離が大きいとUnity-chanの移動処理が走る前にカメラのカメラ処理が走るため、一瞬Unityちゃんが画面から消える、もしくは画面がチラついて見えます。

※2フレーム目のUnity-chanの移動をカメラが追いかけていないため、Unity-chanがカメラに対し正常に表示されません

Cameraの処理だけLateUpdateにする
====

カメラの処理だけLateUpdate関数を使用することで解決します。

LateUpdate関数は全てのUpdate関数が終わった後に実行します。下記のようにChaseUnityChanCamera.csのUpdate関数をLateUpdate関数に変更します。

【ChaseUnityChanCamera.cs】

using UnityEngine;  
using System.Collections;  

public class ChaseUnityChanCamera : MonoBehaviour  
{
    public Transform unityChan;  

    // Update () -> LateUpdate ()に変更  
    void LateUpdate ()  
    {
        var pos = unityChan.position;  
        pos.y = 0.7f;  
        // Unity-chanの方をマイフレーム向くようにする  
        transform.LookAt(pos);  
    }
}
  1. 【1フレーム目】
    1. UpdateTest Update処理 (Unity-chan移動処理)
    2. ChaseUnityChanCamera LateUpdate処理 (カメラがUnity-chanを追いかける処理)
  2. 【2フレーム目】
    1. UpdateTest Update処理 (Unity-chan移動処理)
    2. ChaseUnityChanCamera LateUpdate処理 (カメラがUnity-chanを追いかける処理)

というように必ずカメラの処理がUnity-chanの移動処理の後に来る事が保証された事で表示崩れがなくなりました。

Unityのリファレンスにもこのような説明があります。

LateUpdate: LateUpdate()は、Update()後に一度呼び出されます。Update()で実行される計算は、LateUpdate()が始まる時に完了します。LateUpdate()の一般的な使用方法は三人称カメラです。Update()内でキャラクターを動かし、回転させる場合、LateUpdate()でカメラの移動と回転の計算をすべて実行できます。これにより、カメラがその位置を追跡する前にキャラクターは完全に移動します。

まとめ
====

  1. Update関数同士の順番保証はない
  2. 順番を保証したい場合は、LateUpdate関数で解決するものもある

カメラをUpdateで動かしている際に何か表示がおかしいな、と思った時はUpdate関数を疑ってみるのも1つの手がかりになるかもしれません。

UnityのUpdate関数とLateUpdate関数の狭間でハマる_181

👉 オススメ記事

2021秋 Asset Refreshセール
100以上のアセットがなんと50%OFF!!オオバもいくつか買いました!
期間 : 10月2日午後3時59分まで

👩‍💻 検証環境