上面是Unity官方文檔提供的代碼生命週期圖。
在學習任何程式之前,
我們首先要先明白它的生命週期。
在 Unity 中,
一切的故事,從Awake開始:
Scripts Execution Order:
但是有那麼多個Start,
要怎麼判斷哪個Start先執行呢?
你可以去Project Settings -> Scripts Execution Order 調整順序:
當初始化後
四季開始自己不斷運行:
Coroutine:
協程Coroutine 可以讓我們在主要工作中偷懶去泡一杯咖啡。
yield WaitForSeconds:等待X秒的時間。
yield StartCoroutine:等待另一個人泡完咖啡的時間。
如果你不是用Coroutine,
而是使用Async, Task的方式泡咖啡
要注意更新UI畫面的時候要切換回主要的線程:
Unity Main Thread Dispatcher
強制切回主線程的Github代碼
特殊情況:
Unity 的生命屬性(Attributes):
在 Unity 中,
你可以掛一些帽子(Attributes)在代碼上面
[InitializeOnLoad]:讓腳本在編輯器加載時執行。
[ExecuteInEditMode]:讓腳本在編輯模式下也能執行,而不僅僅是在遊戲運行時。
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]:
在SplashScreen之前執行
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]:
在Awake之前執行
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
在Awake之後執行
[RuntimeInitializeOnLoadMethod]
第一個場景完成讀取之後執行
class MyClass
{
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
    static void OnBeforeSplashScreen()
    {
        Debug.Log("Before SplashScreen is shown and before the first scene is loaded.");
    }
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    static void OnBeforeSceneLoad()
    {
        Debug.Log("First scene loading: Before Awake is called.");
    }
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
    static void OnAfterSceneLoad()
    {
        Debug.Log("First scene loaded: After Awake is called.");
    }
    [RuntimeInitializeOnLoadMethod]
    static void OnRuntimeInitialized()
    {
        Debug.Log("Runtime initialized: First scene loaded: After Awake is called.");
    }
}
以下是測試完整的生命流程的代碼:
using UnityEngine;
using System.Collections;
public class LifecycleMonitor : MonoBehaviour
{
    // 在這裡定義變量
    public float speed = 5f;
    private Rigidbody rb;
    // Awake 函數在所有其他指令之前執行
    void Awake()
    {
        // 初始化變量
        rb = GetComponent<Rigidbody>();
        Debug.Log("Awake: 初始化變量");
    }
    // OnEnable 函數在物體被啟用時執行
    void OnEnable()
    {
        Debug.Log("OnEnable: 物體被啟用");
    }
    // Start 函數在第一次畫面更新之前執行
    void Start()
    {
        Debug.Log("Start: 遊戲開始");
        // 啟動協程
        StartCoroutine(MyCoroutine());
    }
    // Update 函數每一幀都會執行一次
    void Update()
    {
        // 獲取玩家輸入
        float moveHorizontal = Input.GetAxis("Horizontal");
        float moveVertical = Input.GetAxis("Vertical");
        // 計算移動方向
        Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
        // 移動物體
        rb.AddForce(movement * speed);
        
        Debug.Log("Update: 每一幀都在執行");
    }
    // FixedUpdate 函數每一幀都會執行一次,通常用來處理物理運算
    void FixedUpdate()
    {
        // 在這裡處理物理運算
        Debug.Log("FixedUpdate: 處理物理運算");
    }
    // LateUpdate 函數在所有 Update 函數執行完之後執行
    void LateUpdate()
    {
        Debug.Log("LateUpdate: 在所有 Update 之後執行");
    }
    // OnApplicationPause 函數在遊戲暫停時執行
    void OnApplicationPause(bool pauseStatus)
    {
        if (pauseStatus)
        {
            Debug.Log("OnApplicationPause: 遊戲暫停");
        }
        else
        {
            Debug.Log("OnApplicationPause: 遊戲恢復");
        }
    }
    // OnDestroy 函數在物體被刪除時執行
    void OnDestroy()
    {
        Debug.Log("OnDestroy: 物體被刪除");
    }
    // OnApplicationQuit 函數在玩家退出遊戲時執行
    void OnApplicationQuit()
    {
        Debug.Log("OnApplicationQuit: 玩家退出遊戲");
    }
    // 自定義協程
    IEnumerator MyCoroutine()
    {
        Debug.Log("Coroutine: 開始協程");
        yield return new WaitForSeconds(2);
        Debug.Log("Coroutine: 等待了 2 秒");
        yield return new WaitForSeconds(2);
        Debug.Log("Coroutine: 又等待了 2 秒");
    }
}