今回はUnityで当たり前のように使っているUpdateメソッド、FixedUpdateメソッド、LateUpdateメソッドについてみていこうと思います。
これらのメソッドはMonoBehaviourクラスを継承して作成したクラスで呼ばれるようになります。
UnityでC#のファイルを作成した時にデフォルトでMonoBehaviourクラスを継承して新しいクラスが作成されていると思います。
例えばC#でTestClassというファイルを作成したら
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | using UnityEngine; using System.Collections; public class TestClass : MonoBehaviour { // Use this for initialization void Start () { } // Update is called once per frame void Update () { } } |
のようにMonoBehaviourを継承してTestClassが作成され、StartとUpdateメソッドがデフォルトで用意されています。
FixedUpdateやLateUpdateも記述すれば呼ばれるようになります。
JavaScriptで新しいファイルを作成した場合は明示的に表示されていませんがMonobehaviourクラスを継承して作成されています。
ちなみにこのMonobehaviourクラスを継承して作られたクラスはインスタンス化は出来ません。
Updateメソッド
ゲームで何らかの処理をしようと思ったらUpdateメソッド内に記述する事が多いと思います。
Updateメソッドは毎フレーム呼ばれるので、キーボードを押したか?指定した時間が経過したか?目的地についたかどうか?
等を判断する時に便利です。
Updateメソッドが呼ばれるタイミングはアニメーションがレンダリング(画像の生成等)される前に呼ばれます。
なのでUpdateでキャラクターの位置等を変更し、その後キャラクター等のレンダリングが行われるという感じになります。
Time.deltaTime
Updateメソッドはコンピューターの性能によって呼ばれる回数が変わってくるためキャラクターの移動をさせる時等は性能差を考慮したスクリプトにする必要があります。
その為に使用するのがTime.deltaTimeです。
このTime.deltaTimeは最後のフレームを終了するのに要した時間をあらわします。
最後のフレームを終了するのに要した時間って何!?となりそうですが・・・・(^_^;)
つまりは前回のUpdateから今のUpdateが呼び出されるまでの時間ということですね。
その為
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | using UnityEngine; using System.Collections; public class UpdateTest : MonoBehaviour { // 経過時間 private float nowTime; void Start () { nowTime = 0f; } void Update () { // Time.deltaTimeを足す nowTime += Time.deltaTime; // 経過時間を表示 Debug.Log(nowTime); // 10秒を超えたら0に戻す if(nowTime >= 10f) { nowTime = 0f; } } } |
↑のようにスクリプトを作成し、何らかのゲームオブジェクトに設定すればこのゲームオブジェクトが登場してからの経過時間を調べる事が出来ます。
↑が実行例です。
Updateメソッド内でキャラクターの移動をさせる処理を記述する事が多いと思いますが、性能差を考えこのTime.deltaTimeを移動値にかけて利用するようにします。
基礎的なキャラクターの移動に関しては
を参照してください。
LateUpdateメソッド
LateUpdateメソッドはUpdateメソッドが呼ばれた後に実行されるメソッドで中身としてはUpdateと同じです。
用途としてはキャラクターが移動した後にカメラをキャラクターに追従させる時等に使用します。
Updateメソッド内でキャラクターの移動とカメラの追従を同時に行おうとするとうまくカメラが追従してくれない事があります。
そこで、Updateメソッドでキャラクターの移動をさせた後にLateUpdateメソッドでカメラがキャラクターを追従するようにするとうまく出来たりします。
Updateメソッドで何らかの処理をした後に実行したいものがあるならばLateUpdateメソッドを利用するといいですね。
LateUpdateメソッドに関しては他に書く事ないなぁ・・・・(^_^;)
実際に使っている記事は
やブログの右上にある『サイト内検索が出来ます』でLateUpdateで検索して頂くといくつかの例が出てきますので参照してください。
FixedUpdateメソッド
FixedUpdateメソッドはUpdateメソッドと似ていますが、Updateメソッドはゲームオブジェクト等の動作のレンダリング前で、
FixedUpdateメソッドは物理挙動の更新の直前に呼ばれます。
Updateメソッドはコンピュータの性能差で呼ばれる回数が変わりますが、FixedUpdateメソッドは固定フレームレート(1秒間に呼ばれる回数が同じ)で呼ばれます。
フレームレートは1秒間に呼ばれるフレームの回数なのでfps(フレームパーセカンド)で表現します。
1秒間に30回フレームが呼ばれるとしたら30fpsという事ですね。
このフレームレートはUnityメニューのEdit→Project Settings→Timeで設定出来ます。
↑のようにTimeを選択します。
↑のようにインスペクタにTimeManagerが表示され、Fixed TimeStepでフレームレートを変更出来ます。
デフォルトで0.02となっていて0.02秒間に1回フレームが呼ばれる設定になっています。
つまり1フレーム/0.02秒ですね、これを1秒間に直していくと100フレーム/2秒→50フレーム/1秒、つまり50fpsという事になります。
よってFixedUpdateメソッドはデフォルトの設定で1秒間に50回呼び出されると言う事になります。
Fixed TimeStepを変更すれば固定フレームレートを変更出来るのでここを1にすれば1秒毎にFixedUpdateメソッドが呼ばれるようになります。
もっと多くFixedUpdateメソッドが呼ばれるように小さい値を設定する事も出来ますが、FixedUpdateメソッド内での処理が多ければそれだけ処理負荷がかかります。
ここら辺は
Unity公式のタイムとフレームレートの管理のページをご覧ください。
Rigidbodyを使ってゲームオブジェクトに力を加える時はUpdateメソッドではなくFixedUpdateメソッドで行うのがいいとチラホラ見た事があるんですが、
その理由はFixedUpdateメソッドの呼ばれるタイミングが物理挙動の更新の直前に呼ばれる、固定フレームレートで呼ばれるというのがあるんですね。
UpdateメソッドとFixedUpdateメソッドのテスト
UpdateメソッドとFixedUpdateメソッドを見てきたので実際にテストして確認してみましょう。
両方のメソッド内でフレームレートを計算してコンソールに表示してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | using UnityEngine; using System.Collections; public class UpdateFixedUpdateTest : MonoBehaviour { // Update内で使用する秒数 private float nowTime; // FixedUpdate内で使用する秒数1 private float nowTime2; // FixedUpdate内で使用する秒数2 private float nowTime3; // Update内で使用するカウント変数 private int count; // FixedUpdate内で使用するカウント変数 private int count2; void Start () { nowTime = 0f; nowTime2 = 0f; nowTime3 = 0f; count = 0; count2 = 0; Application.targetFrameRate = 20; // フレームレートを変更 } void Update () { nowTime += Time.deltaTime; count++; Debug.Log("Update:" + count / nowTime); } void FixedUpdate() { nowTime2 += Time.fixedDeltaTime; nowTime3 += Time.deltaTime; count2++; Debug.Log("Fixed1:" + count2 / nowTime2); Debug.Log("Fixed2:" + count2 / nowTime3); } } |
Updateメソッド内でUpdateメソッドが呼ばれた回数を計算した秒数で割ってfpsを表示しています。
FixedUpdateメソッド内ではTime.fixedDeltaTimeとTime.deltaTimeを使用して秒数を計算しています。
FixedUpdateメソッド内でTime.deltaTimeを呼び出すと固定フレームレートの値が返されるようなのでその為の実験です。
固定フレームレートの値という事はTime.fixedDeltaTimeの値が返されるという事でしょうか。
今回はTimeManagerのFixed TimeStepを0.02のまま使用します。
それではこのスクリプトを何らかのゲームオブジェクトに設定しUnityを実行してみましょう。
↑が実行最初の結果です。
FixedUpdateは50fpsで呼ばれているのがわかりますね。
Updateも50fpsになってます。
↑がしばらく実行した後の結果です。
FixedUpdateではほぼ50fps、Updateでは60近くになっています。
Updateメソッドは毎フレーム実行されるのでこういう風になりますね。
ゲームのフレームレートはスタンドアロン(パソコンの実行形式)では最大達成可能フレームレート、スマフォ等のモバイル出力された場合は最大達成可能フレームレートより小さくなっています。
このフレームレートはスクリプトから設定する事が可能です。
先ほどのスクリプトにも記述していていましたが、Application.targetFrameRateに値を入れる事で変更する事が可能です。
ここらのフレームレートに関しては
Unityのスクリプトリファレンスに記述されていますが、Quality Settingsの設定によっては無視されます。
↑のようにUnityメニューのEdit→Project Settings→Qualityを選択します。
Quality SettingsのインスペクタでV Sync CountがDon’t Syncの時はスクリプトで設定されたフレームレートが適用されます。
それ以外の場合は無視されると言う事ですね。
それではSync Countの設定をDon’t Syncにして確認してみましょう。
スクリプトでフレームレートを20に設定したのでUpdateのfpsが20付近で止まっています。
UpdateとFixedUpdateでの入力値の取得について
UpdateメソッドとFixedUpdateメソッドの違いについてわかったところで次のようなスクリプトをMainCamera等に取り付けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class UpdateAndFixedUpdateInputTest : MonoBehaviour { // Update is called once per frame void Update() { if(Input.GetKey(KeyCode.Space)) { Debug.Log("Update"); } } void FixedUpdate() { if (Input.GetKey(KeyCode.Space)) { Debug.Log("FixedUpdate"); } } } |
Unityを実行してSpaceキーを押しっぱなしにすると以下のようになります。
UpdateとFixedUpdateではSpaceキーを押したらコンソールにログを出力するという同じ処理をしていますが、実際に出力される回数はUpdateメソッドの方が多くなります。
これはFixedUpdateメソッドはデフォルトでは0.02秒に1回実行されるのでその間はスペースキーを押しても入力されたかどうかの判断をする処理が実行されていない為、押していても入力の判定がされていない為です。
なのでRigidbodyを使った移動等を行う場合はUpdateメソッドで入力値の計算をし、FixedUpdateメソッドで移動の処理を行う方が入力値の取得漏れが少なくなるかもしれません。
キャラクターの移動等ではあまり支障はでなそうですが、ジャンプボタンを押した時にジャンプをさせる時に『押したのにジャンプしない!!』という状況が発生します。
今回はInputManagerを使っていますが、新しい入力システムのInputSystemを使った場合は入力がされた時にイベントが実行されるようにしておくとよりわかりやすいかもしれません。
上の記事の「BehaviourをSend Messagesにして取得」の項目を参照してください。
終わりに
UpdateメソッドとFixedUpdateメソッドの違いはなんとなく理解してましたが、こうやって見ていくと呼ばれるタイミング自体が違うというのが再認識されました。
キャラクターを動かす場合CharacterControllerとRigidbody+コライダの2つのやり方がありますが、
CharacterControllerの場合はUpdateで操作、Rigidbody+コライダの場合はFixedUpdateで操作した方がいい理由がなんとなくわかりますね。
Rigidbodyの場合物理的な挙動(相手方に力を与えたり逆に力を加えられたり)を扱っているのでタイミングとしてはFixedUpdate内で記述した方がいいってことですね。
ふむふむなるほど・・・・・(-_-)
本当にわかっているかどうかはまぁ置いておいて・・・・(^_^;)
なんとなくでも違いがわかったのは良かったと思います。
ふむふむなるほど・・・・・(-_-)