【Unity学習日記01】Unityのライフサイクル

参考:Unity公式マニュアルとUnityライフサイクル

0 まえがき

Unity のライフサイクルとは、Unity スクリプトが起動してから破棄されるまでのプロセスを指し、このプロセス中に、Unity スクリプトは多数のイベント関数をあらかじめ決められた順序で実行します。

これらの関数はすべてシステムによって定義されており、それらを呼び出すには MonoBehaviour クラスを継承する必要があります。スクリプトは任意のゲーム オブジェクトにハングする必要があり、ゲーム オブジェクトはさまざまなスクリプトをマウントでき、各スクリプトは独自のライフ サイクルを実行します。

この記事では、これらのイベント関数を紹介し、実行される順序について説明します。

1 Unity ライフサイクル図

公式マニュアルを参照してください:スクリプト ライフサイクル フローチャート

2 Unityのライフサイクル

2.1 初期化フェーズ

初期化フェーズ

1 最初のシーンをロードする

シーンの開始時に次の関数が呼び出されます。

Awake :
呼び出し時間: スクリプト インスタンスが読み込まれるとき、つまりシーンが読み込まれるとき、またはプレハブがインスタンス化されるとき、Awake は 1 回だけ呼び出されます。
呼び出し条件
ゲームオブジェクトが起動状態にあること(起動時にゲームオブジェクトが非アクティブな場合、起動後までAwakeは呼び出されません。この
呼び出し条件に基づいて、Awake関数が実行されるとき、それが保証されていないことがわかりました)すべてのオブジェクトがロードされ、初期化されていることを確認するため、Awake 関数で他のオブジェクトを検索したり、他のオブジェクトに依存するプロパティを設定したりするなど、オブジェクトの初期化に関連する操作をそこで実行することはできません。これらの操作は Start 関数で実行する必要があります。

OnEnable :
呼び出し時間: この関数は、オブジェクトが使用可能 [1] またはアクティブ化 [2] になるたびに呼び出され、複数回呼び出すことができます。
呼び出し条件: ゲームオブジェクトがアクティブ化されている、ゲームスクリプトが有効化されている。

注:
使用可能: オブジェクトがシーン内にあるかどうか。オブジェクトが使用可能な場合、そのオブジェクトはシーン内に存在し、アクセスできます。gameObject.activeSelf プロパティを使用して、オブジェクトが使用可能かどうかを確認できます。(オブジェクトが突然利用可能になる状況: ゲームの実行中にインスタンス化されます。
Activated : オブジェクトが有効な状態にあるかどうか。オブジェクトが有効な状態にある場合、オブジェクトはレンダリングされ、入力イベントに応答します。 SetActive() 関数を使用してオブジェクトを有効または無効にします。

2 編集者

エディター モードでのみ呼び出される関数:

リセット:
呼び出し時間: ユーザーが検査パネルのリセット ボタンをクリックしたとき、またはコンポーネントが初めて追加されたときに呼び出されます。

OnValidate :
呼び出されたとき: オブジェクトの逆シリアル化時を含め、スクリプトのプロパティが設定されるたびに呼び出されます。これは、シーンがエディタで開かれたときやドメインがリロードされた後など、さまざまな時点で発生する可能性があります。

3 最初のフレーム更新前

Start :
呼び出し時間: MonoBehaviour インスタンスがロードされるとき、つまりシーンがロードされるとき、またはプレハブがインスタンス化されるとき、Start は最初のフレーム更新の前に 1 回だけ呼び出されます。
呼び出し条件: ゲームオブジェクトがアクティブ化されている、ゲームスクリプトが有効化されている。

2.2 物理アップデート段階

物理学のアップデート

1物理フレーム

FixedUpdate :
FixedUpdate は、フレーム レートに関係なく、信頼できるタイマーに基づいて呼び出されます (プロジェクト -> 設定 -> 時間、デフォルトは 0.02 秒、値にアクセスするには Time.fixedDeltaTime を使用します)。オブジェクト (Rigidbody、Force、Collider) の物理プロパティまたは入力イベントを処理する場合、オブジェクトの物理パフォーマンスをよりスムーズにするために、Update の代わりにFixedUpdate を使用する必要があります。

しかし実際には、FixedUpdate は実際の時間間隔に従って実行されるのではなく、Timer の時間間隔に従って実行され、Timer は実際のリアルタイムではなく、その機能は実行環境に非常に類似した時間を作成することです。物理フレームの論理的安定性を実現するための変数。このFixedUpdateの特性のため、このステップでは物理関連の処理のみを実行し、他のタイプの処理(ネットワーク・フレーム同期など)をこのステップに含めないことをお勧めします。

2 トリガー/コリジョン

OnTriggerXXX :
トリガーが起動されると呼び出されます。

OnCollisionXXX :
衝突イベントが発生したときに呼び出されます。

3 コルーチン: 物理フレームの終わり

Yield WaitForFixedUpdate :
物理フレームが実行されると、このコルーチンにジャンプします コルーチンの呼び出しはメソッドとは異なります コードの中で行き詰まりポイントを設定すると理解できます プログラムがタイミングで実行されるときこのスタック ポイントに一致する スタック ポイント以降のコードは実行を継続します。

public class Test : MonoBehaviour{
    
    
    void Awake(){
    
    
    	//数字代表执行顺序
        Debug.Log("1");
        StartCoroutine(TestCoroutine());
        Debug.Log("3");
    }
    void FixedUpdate(){
    
    
        Debug.Log("4");
    }
    //协程
    IEnumerator TestCoroutine(){
    
    
        Debug.Log("2");
        yield return new WaitForFixedUpdate(); //卡点:物理帧结束
        Debug.Log("5");                      
    }
}

2.3 入力イベントステージ

入力イベント

マウス、キーボード、タッチ スクリーン、ハンドルなどのさまざまな入力イベントがこの段階でトリガーされます。この時点で、物理的な更新は実行されています (物理的な更新が必要な場合) が、論理的な更新とレンダリングはこのトリガーのタイミングを理解するには、この方法でのみコード ロジックをよりよく理解できます。

2.4 ゲームロジックステージ

ゲームロジック

1フレーム更新

Update :
フレームごとに 1 回呼び出されますが、システム パフォーマンスとゲーム サイズの違いにより、各フレームの更新頻度も異なるため、Update メソッドでタスクが時間通りに完了することをあまり期待しないでください。

Update とFixedUpdate は実際には同じスレッドを使用します。更新がループ内で処理される方法は、更新が完了した後、前のフレームから現在までのオフセット時間に基づいて次の更新を実行するかどうかを決定することです。コールバック関数。コールバック関数である限りコンテキストの転送が失われるため、コールバックを減らしたい場合は、Update メカニズムを自分で実装し、Update の代わりに仮想関数を使用することを検討できます。

2 マルチコルーチンポイント判定

1.yield null
2.yield WaitForSeconds
3.yield WWW: ネットワーク タスクの実行が完了すると、WWW 以降の操作が現在のフレームのこの時点で実行されます。通常、リソースを非同期にロードするために使用されます。
4.yieldStartCoroutine

3以降に更新されました

LateUpdate :
このメソッドは、各フレームで Update メソッドが呼び出された後に呼び出されます。LateUpdate が開始されると、Update で実行されるすべての計算が完了しているため、LateUpdate は通常、二次計算に使用されます。

LateUpdate の一般的な用途は、三人称カメラのフォローです。Update 内でキャラクターを移動したり回転させたりする場合は、すべてのカメラの移動と回転の計算を LateUpdate で実行できます。これにより、カメラがその位置を追跡する前に、キャラクターが完全に移動することが保証されます。

2.5 レンダリング段階

レンダリング
OnGUI :
OnGUI() メソッドは、Unity の GUI システムがレンダリングされる前に呼び出され、通常、ボタン、ラベル、スライダーなどの UI 要素をゲーム インターフェイスに表示するために使用されます。ゲーム インターフェイスに UI 要素を表示する必要がある場合は、OnGUI() メソッドに関連するコードを記述できます。OGUI() はフレームごとに複数回呼び出されます。

OnGUI() メソッドはメイン スレッドでのみ呼び出すことができ、他のスレッドでは呼び出すことができないことに注意してください。そうしないと、プログラム例外が発生します。さらに、OnGUI() メソッドの呼び出しは Unity の GUI システムによって自動的にトリガーされるため、このメソッドを手動で呼び出す必要はありません。

さらに、OnGUI 関数は、Unity の新しいバージョンでは「非推奨」としてマークされており、新しいプロジェクトでの使用は推奨されません。UGUI (Unity GUI) や IMGUI (イミディエイト モード GUI) などの新しい UI システムを使用することをお勧めします。

2.6 一時停止フェーズ

一時停止
OnApplicationPause :
この関数はフレームの最後に呼び出されます (通常のフレーム更新間の一時停止を効果的に検出します)。OnApplicationPause が呼び出された後、追加のフレームが生成され、ゲームが一時停止状態を示すグラフィックを表示できるようになります。

2.7 終了フェーズ

終了フェーズ
ApplicationQuit :
アプリケーションが終了すると、これらのオブジェクトにハングしている MonoBehaviour スクリプトを含む、実行中のすべてのシーンとオブジェクトが破棄されます。この場合、アプリケーションを終了する前に特定の操作を実行する必要がある場合は、OnApplicationQuit 関数を使用してこれを実現できます。エディターでは、ユーザーが再生モードを停止すると関数が呼び出されます。

アプリケーションが強制終了またはクラッシュした場合、OnApplicationQuit 関数は呼び出されないことに注意してください。

OnDisable :
スクリプトまたはゲーム オブジェクトが無効になったときに呼び出されます。通常、ゲーム オブジェクトが無効になっているときに、オーディオ再生の停止、アニメーション再生の停止など、クリーンアップ操作を実行したり、特定のアクションを停止したりするために使用されます。通常、これらの操作は OnEnable 関数で開始し、OnDisable 関数で停止する必要があります。これにより、ゲーム オブジェクトが有効または無効になったときに、アクションの開始と停止が対称になり、予期しない動作が回避されます。

ゲーム オブジェクトが破棄されると、スクリプトの OnDisable 関数を含め、その関連コンポーネントがすべて破棄されるため、ゲーム オブジェクトが破棄されるときには OnDisable 関数は呼び出されないことに注意してください。ゲーム オブジェクトが破棄されたときにクリーンアップ操作を実行する必要がある場合は、OnDestroy 関数を使用してこれを実現できます。

OnDestory :
ゲームオブジェクトが破棄されたときに呼び出されます。OnDestroy 関数は通常、ファイルを閉じる、メモリを解放するなど、ゲーム オブジェクトが破棄されたときにクリーンアップ操作を実行したり、リソースを解放したりするために使用されます。

面接での3つの質問

1. Awake と Start の違いは何ですか?
①呼び出しのタイミングが違う。Awake はスクリプト インスタンスがロードされるときに呼び出され、Start は最初のフレームが更新される前に呼び出されます。つまり、Awake はスクリプト インスタンスの生成時に呼び出され、Start はフレーム上で呼び出されます。たとえば、Update で GameObject をインスタンス化すると、Awake は同じフレームですぐに実行され、Start は次のフレームで実行されます。
②呼び出し条件が異なります。Awake は、スクリプトが有効かどうかに関係なく、スクリプト インスタンスがロードされるときに呼び出されます。Start は、スクリプトが有効になっている場合にのみ呼び出すことができます。
③使い方が違う。一般に、Awake で変数または状態を初期化しますが、遅延初期化が必要な場合や他のゲーム オブジェクトのコンポーネントを取得する場合は、Start を使用できます。

2. Awake、Start、OnEnable の違いは何ですか?
主な違いは、Awake と Start はオブジェクトのライフ サイクルで 1 回だけ呼び出されることです。オブジェクトが非アクティブ化されてから再アクティブ化されると、スクリプト内の Awake と Start は再実行されませんが、OnEnable は実行されるたびに呼び出されます。をアクティブ化して実装します。

3. シーンには 2 つのオブジェクトがありますが、シーンがロードされると、それらの Awake 機能が同時に実行されますか?
Unity はシングルスレッドであるため、これらは同時に実行されず、順番に実行されます。それらの実行順序はUnityによって決定され、特定の条件が満たされた場合の実行順序を指定できます。

実行順序を指定できるかどうかは、主に 2 つのオブジェクトが同じスクリプトの異なるインスタンスであるかどうかによって決まります。
「yes:」を指定できない場合、これら 2 つのオブジェクトのイベント関数の実行順序は不定となります。
そうでない場合:指定可能。「プロジェクト設定」ウィンドウの「スクリプト実行順序」パネルを使用します)。たとえば、EngineBehaviour と SteeringBehaviour という 2 つのスクリプトがある場合、EngineBehaviours が常に SteeringBehaviours より前に更新されるようにスクリプトの実行順序を設定できます。

また、1 つのオブジェクトに対して MonoBehaviour を継承するスクリプトが 2 つある場合、それらの Awake はスクリプトが追加された順序で実行されます。

4.UpdateとFixedUpdateの違いは何ですか?
Update() メソッドは、各フレームがレンダリングされる前に呼び出され、通常、プレーヤー入力、アニメーション コントロール、オーディオ再生などのゲーム オブジェクトの状態や動作を更新するために使用されます。呼び出し時間は一定ではなく、フレーム レートやコンピュータのパフォーマンスに依存するため、物理関連以外の計算の処理に適しています。

FixedUpdate() メソッドは、固定時間間隔に従って呼び出されます。通常、デフォルトは 1 秒あたり 50 回です。物理エンジンの固定時間間隔が固定されているため、各フレームでのFixedUpdate()メソッドの呼び出し数が固定されており、モーションや衝突検出などの物理関連の計算に適しています。

さらに、Update() メソッドとは異なり、FixedUpdate() メソッドは物理エンジンに基づいて一定の間隔で呼び出されるため、一時停止、再開、または無効にすることはできません。

5. 衝突検出が必要なオブジェクトが複数ある場合、どの機能を使用する必要がありますか?
最も一般的なアプローチは、物理エンジンによって提供される衝突検出メカニズムを使用することです。つまり、Collider コンポーネントと Rigidbody コンポーネントをゲーム オブジェクトに追加し、スクリプト内で OnCollisionXXX などのイベント関数を使用して関連ロジックを処理します。

物理エンジンが提供する衝突検出メカニズムを使用しない場合は、Raycast や OverlapSphere などの関数を衝突検出に使用することもできますが、これらの関数は手動で呼び出す必要があり、Unity ライフサイクルのイベント関数ではありません。

6. コルーチンとは何ですか?
Unity のコルーチンは、実行中に一時停止し、指定された時間または条件が満たされた場合に実行を継続できる特別な関数です。Unity のコルーチンはイテレータ (yield) に基づいて実装されており、yield return ステートメントでコルーチンの実行を一時停止し、yield Break ステートメントでコルーチンの実行を終了できます。

コルーチンの目的:

1. 遅延実行: コルーチンは、一定時間の遅延後にアニメーションの再生や効果音の再生など、指定された操作を実行できます。
2. リソースを動的にロードする: コルーチンはリソースを非同期にロードし、ゲームの実行中にシーン、モデル、テクスチャ、その他のリソースを動的にロードするなど、リソースのロードが完了した後に指定された操作を実行できます。
3. アニメーション制御:コルーチンを使用して、アニメーションの状態を一定時間内に徐々に変更したり、アニメーションをループさせたりするなど、アニメーションの再生を制御できます。
4. マルチスレッド シミュレーション: コルーチンはマルチスレッドの効果をシミュレートし、メイン スレッドでコルーチンを実行して一時停止し、ファイルのダウンロードやファイルの解凍などの指定された操作を別のスレッドで実行できます。
5. 共同作業: コルーチンは、1 つのスクリプト内で別のスクリプトの実行順序やパラメータ転送を制御するなど、異なるスクリプト間で共同作業できます。

例:
プレイヤーがアイテムを取得したときに、「+1」のテキスト アニメーションを表示し、1 秒待ってから自動的に消えるようにしたいとします。コルーチンを使用してこの効果を実現できます。

public class PickupItem : MonoBehaviour{
    
    
    public GameObject pickupEffect;

    private void OnTriggerEnter(Collider other){
    
    
        if (other.CompareTag("Player")){
    
    
            // 播放拾取特效
            Instantiate(pickupEffect, transform.position, Quaternion.identity);
            // 开始协程
            StartCoroutine(DisplayText());
        }
    }
    IEnumerator DisplayText(){
    
    
        // 显示“+1”文本
        var text = GameObject.Instantiate(Resources.Load<GameObject>("Text"));
        text.transform.position = transform.position;
        text.GetComponent<TextMesh>().text = "+1";
        // 等待1秒
        yield return new WaitForSeconds(1f);
        // 销毁文本
        Destroy(text);
    }
}

7. シーンを切り替えるときのライフサイクルを管理するにはどうすればよいですか?
① シーン内でさまざまなゲーム オブジェクトを使用してさまざまな機能と状態を管理し、ライフサイクル管理をより明確かつ簡単にします。
②シーン切り替え時に保持する必要があるゲームオブジェクトに対してDontDestroyOnLoadメソッドを使用し、シーン切り替え時にゲームオブジェクトが破壊されないようにします。
③シーンの切り替え時に破棄する必要があるゲームオブジェクトに対してSceneManager.LoadSceneメソッドを使用すると、シーンの切り替え時にこれらのゲームオブジェクトが破棄され、リソースリークやパフォーマンスの問題が回避されます。
④ ゲーム オブジェクトの Awake メソッドと OnDestroy メソッドを使用して、ゲーム オブジェクトの作成時にいくつかの初期化操作を実行し、ゲーム オブジェクトが破棄されるときにいくつかのクリーンアップ操作を実行して、ゲーム オブジェクトがライフ サイクル中に常に正しい状態になるようにします。

8. Unity のライフサイクルとメモリ管理の関係は何ですか?
Unity では、ゲーム オブジェクトまたはコンポーネントが作成されると、そのデータと状態を保存するために一定量のメモリ領域が割り当てられます。このゲーム オブジェクトまたはコンポーネントが必要でなくなった場合、Unity は自動的にメモリ スペースを解放し、他のオブジェクトまたはコンポーネントがメモリ スペースを使用できるようにします。このプロセスでは、ライフサイクルが重要な役割を果たします。たとえば、ゲーム オブジェクトが破棄されると、Unity は自動的にオブジェクトの OnDestroy メソッドを呼び出し、ゲーム オブジェクトが占有していたメモリ領域が解放されます。同様に、コンポーネントが無効化または破棄されると、Unity はこのコンポーネントが占有しているメモリ空間を自動的に解放します。

自動メモリ管理に加えて、Unity はリソース管理、オブジェクト プールなどのいくつかの手動メモリ管理機能も提供します。これらの機能は、開発者がメモリの使用と解放をより適切に制御するのに役立ち、それによってゲームのパフォーマンスと安定性が向上します。

おすすめ

転載: blog.csdn.net/manpi/article/details/129968738