unity3d中腳本生命週期(MonoBehaviour lifecycle)

自:http://blog.csdn.net/qitian67/article/details/18516503   (PS:他這裏有許多文章,大家看下)

最近在做一個小示例,發現類繼承於MonoBehaviour的類,有很多個方法,於是乎必然要問出一個問題:這麼多個方法,執行先後順序是如何的呢?內部是如何進行管理的呢?於是在網上找了許多資料,發現了Richard Fine在2012年就已經發布了一篇文章,而且講得算是相當深入,並且很有道理的,這裏加上我的一些嘗試與思考,分享給大家。

先貼上圖,大家有個直觀認識:

 

 

接下來,做出一下講解:最先執行的方法是Awake,這是生命週期的開始,用於進行激活時的初始化代碼,一般可以在這個地方將當前腳本禁用:this.enable=false,如果這樣做了,則會直接跳到OnDisable方法執行一次,然後其它的任何方法,都將不再被執行。

如果當前腳本處於可用狀態,則正常的執行順序是繼續向下執行OnEnable,當然我們可以在另外一個腳本中實現這個腳本組件的啓動:this.enab=true;

再向下執行,會進行一個判斷,如果Start方法還沒有被執行,則會被執行一次,如果已經被執行了,則不會再被執行。這是個什麼意思呢?我們可以在某個腳本中將組件禁用this.enable=false,再啓用時會到OnEnable處執行,這時繼續向下走,發現Start執行過了,將不再被執行。比如說:第一次啓用時,將怪物的初始位置定在了(0,0,0)點,然後怪物可能會發生了位置的變換,後來被禁用了,再次啓用時,不會讓怪物又回到初始的(0,0,0)位置。

繼續向後執行,就是Update了,然後是FixUpdate,再然後是LateUpdate,如果後面寫了Reset,則會又回到Update,在這4個事件間可以進行循環流動。

再向後執行,就進入了渲染模塊(Rendering),非常重要的一個方法就是OnGUI,用於繪製圖形界面。當然,如果你使用了NGUI,這個生命週期的事情你就不用考慮了。

再向後,就是卸載模塊(TearDown),這裏主要有兩個方法OnDisable與OnDestroy。當被禁用(enable=false)時,會執行OnDisable方法,但是這個時候,腳本並不會被銷燬,在這個狀態下,可以重新回到OnEnable狀態(enable=true)。當手動銷燬或附屬的遊戲對象被銷燬時,OnDestroy纔會被執行,當前腳本的生命週期結束。

 

特別要強調的是:這裏雖然可以使用C#來寫代碼,但是這個類構造對象的生命週期,與MonoBehaviour的生命週期,是完全不同的。

 

可以通過如下示例:對腳本進行驗證(兩個腳本添加到同一個遊戲對象上):

腳本1Monster1:

    void OnBecameInvisible()
    {
        Debug.Log("invisible");
        MonsterController mc1 = this.gameObject.GetComponent<MonsterController>();
        mc1.enabled = false;
    }


    void OnBecameVisible()
    {
        Debug.Log("visible");
        MonsterController mc1 = this.gameObject.GetComponent<MonsterController>();
        mc1.enabled = true;
    }

腳本2MonsterController:

    void Awake()
    {
        Debug.Log("awake");
        this.enabled = false;
    }


    void OnEnable()
    {
        Debug.Log("enable");
        this.enabled = true;
    }


    void Start()
    {
        Debug.Log("start");
        //this.gameObject.SetActive(false);
    }


    void Update()
    {
        Debug.Log("update");
    }


    void OnGUI()
    {
        Debug.Log("gui");
    }
    void OnDisable()
    {
        Debug.Log("disable");
    }


    void OnDestroy()
    {
        Debug.Log("destroy");
    }

 

如果您覺得有不對之處,歡迎指正,爲了技術進步,我們一起努力。

Richard Fine的文章地址:點擊閱讀

 

補充官網的信息:

事件函數的執行順序

Unity 腳本中有許多按預設順序以腳本身份運行的事件函數。其執行順序如下:

 

加載第一個場景

啓動場景時調用這些函數(爲場景中的每個對象調用一次)。

  • Awake: 始終在調用任何 Start 函數之前和實例化預設之後調用此函數。(如果遊戲對象 (GameObject) 在啓動期間處於非活動狀態,則直到其處於活動狀態時或調用添加至其本身的任何腳本中的函數時,再調用 Awake 函數。)紅字部分是圖中沒有提到的,特別需要注意!!!綠色的部分通關測試是不正確的
  • OnEnable: (僅當對象 (Object) 處於活動狀態時調用此函數):程序會在啓用該對象後立即調用此函數。上述現象會在創建了實例化的 MonoBehaviour 後發生,例如加載了級別或對含腳本組件的遊戲對象 (GameObject) 進行實例化後。
 

第一幀更新之前

  • Start: 只要啓用腳本實例,即可在更新第一幀之前調用 Start 函數。
 

插值幀

  • OnApplicationPause: 程序檢測到暫停時,會在幀的結尾處調用此函數,這在常規幀更新期間很有效。調用 OnApplicationPause後,程序將運行另一幀來顯示提示暫停狀態的圖形。
 

更新順序

有幾個不同的事件有助於追蹤遊戲邏輯與交互、動畫、相機位置等內容。常用的方法是運行Update() 函數中的大部分任務,但也可使用其他函數。.

 
  • FixedUpdate: 通常,FixedUpdate() 的調用頻率高於 Update()。如果幀速率較低,則可在一幀中多次調用此函數,如果幀速率較高,則可能完全無法在幀間調用此函數。程序調用 FixedUpdate() 後將立即執行所有物理計算和更新。在 FixedUpdate() 中應用移動計算時,無需將您的值與 Time.deltaTime 相乘。這是因爲,程序是在可靠的計時器上調用FixedUpdate(),與幀速率無關。
     
  • Update: 在每幀上調用一次 Update() 函數。它是用於幀更新的主要 workhorse 函數。
     
  • LateUpdate: 完成 Update() 調用後,在每幀上調用 LateUpdate()。Update() 中執行的所有計算都將在 LateUpdate() 開始之前結束。LateUpdate() 的常規使用記錄由第三人稱相機跟蹤。如果在 Update() 中移動和旋角色,則可在 LateUpdate() 中計算所有相機移動和旋。這將確保在相機跟蹤其位置之前完整移動該角色。
 

渲染

  • OnPreCull: 在相機剔除場景之前調用此函數。相機可見的對象取決於剔除。OnPreCull 函數調用發生在剔除之前。
  • OnBecameVisible/OnBecameInvisible: 在對象對於相機可見/不可見時調用此函數。
  • OnWillRenderObject: 如果對象可見,則爲每個相機調用一次此函數。
  • OnPreRender: 在相機開始渲染場景之前調用此函數。
  • OnRenderObject: 在完成所有常規場景渲染後調用此函數。此時,可使用 GL 類或 Graphics.DrawMeshNow 繪製自定義幾何圖形。
  • OnPostRender: 在相機完成場景渲染後調用此函數。
  • OnRenderImage(僅限專業版): 在完成場景渲染後調用此函數,以便對屏幕圖像進行後處理。
  • OnGUI: 在每幀上多次調用此函數,以響應 GUI 事件。程序首先將處理 Layout 和 Repaint 事件,然後再處理每個輸入事件的 Layout 和 keyboard/鼠標事件。
  • OnDrawGizmos 用於在場景視圖中繪製小圖示 (Gizmos),以實現可視化目的。
 

協同程序

正常的協同程序更新是在返回 Update 函數之後運行。協同程序是可自行停止運行 (yield),直到給定的 YieldInstruction 結束再繼續運行的函數。 協同程序 (Coroutines) 的不同用途:

  • yield; 在下一幀上調用所有 Update 函數後,協同程序將繼續運行。
  • yield WaitForSeconds(2); 在指定的時間延遲之後,爲此幀調用所有 Update 函數之後繼續運行
  • yield WaitForFixedUpdate(); 在所有腳本上調用所有 FixedUpdate 後繼續運行
  • yield WWW 完成 WWW 下載後繼續運行。
  • yield StartCoroutine(MyFunc); 連接協同程序,並等待 MyFunc coroutine 首先結束。
 

對象 (Object) 被銷燬時

  • OnDestroy: 完成所有幀更新後,在當前對象的最後一幀上調用此函數(可能爲響應 Object.Destroy 或在關閉場景時銷燬此對象)。

退出時

程序將在場景的所有活動對象上調用這些函數:

  • OnApplicationQuit: 在退出應用程序之前,程序會在所有遊戲對象上調用此函數。在編輯器中,用戶停止播放模式時,程序將調用此函數。在網頁播放器中,此函數會在網頁視圖關閉時調用。
  • OnDisable: 此函數會在行爲被禁用或不活動時調用。
 

綜上所述,任何給定腳本的執行順序爲:

  • 調用所有 Awake
  • 調用所有 Start
  • 同時進行(朝向可變增量時間)
    • 所有 FixedUpdate 函數
    • 物理模擬
    • OnEnter/Exit/Stay 觸發函數
    • OnEnter/Exit/Stay 碰撞函數
     
  • 剛體插值應用 transform.position 和旋
  • OnMouseDown/OnMouseUp 等事件
  • 所有 Update 函數
  • 將動畫優化爲高級、混合並應用動畫,以進行變換
  • 所有 LateUpdate 函數
  • 渲染

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章