読者です 読者をやめる 読者になる 読者になる

渋谷ほととぎす通信

完全趣味でやってるUnityメモ。説明できないところを説明できるようにするための個人ブログ。昨日の自分より少しでも大きく慣れるように。。。 ※所属団体とは一切関係がありません

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


f:id:esakun:20160703112026p:plain

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

  • Update関数
  • LateUpdate関数
  • FixedUpdate関数

それぞれ役割と意味があるのですが、今回は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));
    }
}

f:id:esakun:20160703103528g:plain

このようにUnity-chanが毎フレームX軸方向に2cm平行移動するようになりました。
※歩くアニメーションはUnity-chan同梱のAnimationClipを再生しています

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

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

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

f:id:esakun:20160703104448p:plain

【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);
    }
}

f:id:esakun:20160703103606g:plain

すると、このように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関数の順番というのは保証されていません。
※これは、Start関数Awake関数も同様です。

実際の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移動処理)
      ↑↑ 1フレームと比べると順番が逆になっている

これがどのような問題になるかというと、今回のサンプルでは、移動距離が少なかったため気になりませんが、移動距離が大きいと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()でカメラの移動と回転の計算をすべて実行できます。これにより、カメラがその位置を追跡する前にキャラクターは完全に移動します。

Unity - マニュアル: イベント関数の実行順 より

まとめ

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

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

開発環境

  • Unity v5.3.5f1
  • MacOS 10.11.5

f:id:esakun:20160208012216j:plain