Update関数でやりがちな罠
Unityでソースコードを書こうとするならまず初めに触れ合うことになる馴染み深い関数、Update。
でも、知っているようで忘れがちな細かい仕様について紹介します。
Update関数は毎フレーム実行されます
当たり前だけど、これが重要。
例えばこのコード。
void Update()
{
var obj = GameObject.Find("Hoge");
obj.transform.localPosition = new Vector3(x, y, z);
}
GameObject.Findは実行コストの高い関数。これが毎フレーム実行されると、実行が重くなる原因に・・・
他にも、毎回変更があるわけでもないテキストUIを、毎回
void Update()
{
HogeText.text = hogeString;
}
とかで更新していると、見た目変更がなくても毎フレーム描画が走って地味に重い原因になってたりします。
Update関数の実行順は順不同です
どういうことかというと、クラスAのUpdate関数とクラスBのUpdate関数、どっちが先に実行されるのか決まっていないということです。
さっきのフレームではクラスA.Update()
が先に実行されてたのに、今のフレームではクラスB.Update()
が先に実行されたりします。
カメラがプレイヤーを追いかけるように実装したいのに、カメラ.Update()
内でプレイヤーの位置を見てカメラ位置を修正してるはずが描画がガクガクする・・・
そんな問題の原因がこれです。
この例の場合の解決策は、カメラ.LateUpdate()
内でプレイヤーの位置を見るように変更することです。
LateUpdate()
はすべてのUpdate関数が実行されたあとに実行される関数なので、Updateが実行されたあとに実行したい処理はLateUpdateで行うのが良いと思います。
Update関数は描画の更新、FixedUpdate関数は物理計算の更新
以下リンク先に、Unity公式のライフサイクル図があります。
https://docs.unity3d.com/jp/460/Manual/ExecutionOrder.html
これを見ていただくと各関数の実行順が分かるのですが、 Updateのあとにコルーチンの処理が入り、その後LateUpdateが入り、その後にレンダリング処理が入っているのが分かると思います。
このようにUpdateで変更があれば、毎フレームレンダリング処理が入るようになっています。
transform.position = new Vector3(x, y, z);
などを使って直接現在位置を変更するなら、描画の更新が入ります。
この処理はUpdate()に書くべきということですね。
ところで、ライフサイクル上、Updateの上にFixedUpdate
という処理が入っているのが分かるかと思います。
これはフレーム単位ではなく、毎秒30回、など決まった回数決まった間隔で必ず呼ばれる関数です。
FixedUpdate
処理があるグループは「Physics」となっています。要は、物理計算です。
rigidbody.AddForce(force);
などを使って物体を動かしたい場合、この処理を書くのはUpdateではなく FixedUpdateが向いている、というのがなんとなく分かるかと思います。
まとめ
- Update関数では重い処理や不必要な描画更新をしない
- Update内の処理を受けて更新したい内容はLateUpdateに書く
- 描画更新はUpdate関数
- 物理計算はFixedUpdate関数
余談ですが、それぞれの関数の実行順が分からなくなったとき、私は上記のライフサイクル図をよく見直させてもらってます。
実行順がわかると実装の時も気をつけられるようになるので、何度も見直したりブックマークしてたりするのがおすすめです。