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)); } }
このようにUnity-chanが毎フレームX軸方向に2cm平行移動するようになりました。
※歩くアニメーションはUnity-chan同梱のAnimationClipを再生しています
Unity-chanをカメラで追いかけてみる
Unity-chanが動いているだけでしたが、その動きをカメラで追いかけてみます。
下記のChaseUnityChanCamera.cs
をカメラにAddComponentして、下図のようにUnity Chanの参照を渡して再生します。
【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-chanの方を毎フレームカメラ向くようになりました。
ここからが本題で、このままでは不完全です。
- 【1フレーム目】
- UpdateTest Update処理 (Unity-chan移動処理)
- ChaseUnityChanCamera Update処理 (カメラがUnity-chanを追いかける処理)
- 【2フレーム目】
- UpdateTest Update処理 (Unity-chan移動処理)
- ChaseUnityChanCamera Update処理 (カメラがUnity-chanを追いかける処理)
という決まった順番で実行されれば、特に問題は起きません。
しかし、、、
実際はUpdate関数の順番というのは保証されていません。
※これは、Start関数Awake関数も同様です。
実際のUpdate関数同士の処理順番
- 【1フレーム目】
- UpdateTest Update処理 (Unity-chan移動処理)
- ChaseUnityChanCamera Update処理 (カメラがUnity-chanを追いかける処理)
- 【2フレーム目】
- ChaseUnityChanCamera Update処理 (カメラがUnity-chanを追いかける処理)
- 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フレーム目】
- UpdateTest Update処理 (Unity-chan移動処理)
- ChaseUnityChanCamera LateUpdate処理 (カメラがUnity-chanを追いかける処理)
- 【2フレーム目】
- UpdateTest Update処理 (Unity-chan移動処理)
- ChaseUnityChanCamera LateUpdate処理 (カメラがUnity-chanを追いかける処理)
というように必ずカメラの処理がUnity-chanの移動処理の後に来る事が保証された事で表示崩れがなくなりました。
Unityのリファレンスにもこのような説明があります。
LateUpdate: LateUpdate()は、Update()後に一度呼び出されます。Update()で実行される計算は、LateUpdate()が始まる時に完了します。LateUpdate()の一般的な使用方法は三人称カメラです。Update()内でキャラクターを動かし、回転させる場合、LateUpdate()でカメラの移動と回転の計算をすべて実行できます。これにより、カメラがその位置を追跡する前にキャラクターは完全に移動します。
まとめ
- Update関数同士の順番保証はない
- 順番を保証したい場合は、LateUpdate関数で解決するものもある
カメラをUpdateで動かしている際に何か表示がおかしいな、と思った時はUpdate関数を疑ってみるのも1つの手がかりになるかもしれません。
開発環境
- Unity v5.3.5f1
- MacOS 10.11.5