Unity-特性了解自動內(nèi)存管理事件函數(shù)的執(zhí)行順序
行 Unity 腳本會按預(yù)定順序執(zhí)行大量事件函數(shù)。本頁面將介紹這些事件函數(shù),并說明它們的執(zhí)行順序。
腳本生命周期概述
下圖概括了 Unity 如何在腳本的生命周期內(nèi)對事件函數(shù)進行排序以及重復(fù)執(zhí)行這些事件函數(shù)。
有關(guān)各種事件函數(shù)的更多信息,請參閱以下部分:
加載第一個場景
Editor
在第一次幀更新之前
幀之間
更新順序
動畫更新循環(huán)
渲染
協(xié)程
銷毀對象時
退出時
腳本生命周期流程圖

注意:有些瀏覽器不支持 SVG 圖像文件。如果以上圖像未正確顯示(例如,如果看不到任何文字),請嘗試其他瀏覽器,例如?Google Chrome?或?Mozilla Firefox。
加載第一個場景
場景開始時將調(diào)用以下函數(shù)(為場景中的每個對象調(diào)用一次)。
Awake:始終在任何 Start 函數(shù)之前并在實例化預(yù)制件之后調(diào)用此函數(shù)。(如果游戲?qū)ο笤趩悠陂g處于非活動狀態(tài),則在激活之后才會調(diào)用 Awake。)
OnEnable:(僅在對象處于激活狀態(tài)時調(diào)用)在啟用對象后立即調(diào)用此函數(shù)。在創(chuàng)建 MonoBehaviour 實例時(例如加載關(guān)卡或?qū)嵗哂心_本組件的游戲?qū)ο髸r)會執(zhí)行此調(diào)用。
OnLevelWasLoaded:執(zhí)行此函數(shù)可告知游戲已加載新關(guān)卡。
請注意,對于添加到場景中的對象,在為任何對象調(diào)用 Start 和 Update 等函數(shù)之前,會為_所有_腳本調(diào)用 Awake 和 OnEnable 函數(shù)。當(dāng)然,在游戲運行過程中實例化對象時,不能強制執(zhí)行此調(diào)用。
Editor
Reset:調(diào)用 Reset 可以在腳本首次附加到對象時以及使用?Reset?命令時初始化腳本的屬性。
在第一次幀更新之前
Start:僅當(dāng)啟用腳本實例后,才會在第一次幀更新之前調(diào)用 Start。
對于添加到場景中的對象,在為任何腳本調(diào)用 Update 等函數(shù)之前,將在所有腳本上調(diào)用 Start 函數(shù)。當(dāng)然,在游戲運行過程中實例化對象時,不能強制執(zhí)行此調(diào)用。
幀之間
OnApplicationPause:在幀的結(jié)尾處調(diào)用此函數(shù)(在正常幀更新之間有效檢測到暫停)。在調(diào)用?OnApplicationPause?之后,將發(fā)出一個額外幀,從而允許游戲顯示圖形來指示暫停狀態(tài)。
更新順序
跟蹤游戲邏輯和交互、動畫、攝像機位置等的時候,可以使用一些不同事件。常見方案是在?Update?函數(shù)中執(zhí)行大多數(shù)任務(wù),但是也可以使用其他函數(shù)。
FixedUpdate:調(diào)用?FixedUpdate?的頻度常常超過?Update。如果幀率很低,可以每幀調(diào)用該函數(shù)多次;如果幀率很高,可能在幀之間完全不調(diào)用該函數(shù)。在?FixedUpdate?之后將立即進行所有物理計算和更新。在?FixedUpdate?內(nèi)應(yīng)用運動計算時,無需將值乘以?Time.deltaTime。這是因為?FixedUpdate?的調(diào)用基于可靠的計時器(獨立于幀率)。
Update:每幀調(diào)用一次?Update。這是用于幀更新的主要函數(shù)。
LateUpdate:每幀調(diào)用一次?LateUpdate__(在?Update__ 完成后)。LateUpdate?開始時,在?Update?中執(zhí)行的所有計算便已完成。LateUpdate?的常見用途是跟隨第三人稱攝像機。如果在?Update?內(nèi)讓角色移動和轉(zhuǎn)向,可以在?LateUpdate?中執(zhí)行所有攝像機移動和旋轉(zhuǎn)計算。這樣可以確保角色在攝像機跟蹤其位置之前已完全移動。
動畫更新循環(huán)
Unity 評估動畫系統(tǒng)時,將調(diào)用以下函數(shù)和?Profiler?標(biāo)記。
OnStateMachineEnter:在狀態(tài)機更新 (State Machine Update)?步驟中,當(dāng)控制器的狀態(tài)機進行流經(jīng) Entry 狀態(tài)的轉(zhuǎn)換時,將在第一個更新幀上調(diào)用此回調(diào)。在轉(zhuǎn)換到?StateMachine?子狀態(tài)時不會調(diào)用此回調(diào)。
僅當(dāng)動畫圖中存在控制器組件(例如,AnimatorController、AnimatorOverrideController?或?AnimatorControllerPlayable)時才會發(fā)生此回調(diào)。
注意:將此回調(diào)添加到?StateMachineBehaviour?組件會禁用多線程的狀態(tài)機評估。OnStateMachineExit:在狀態(tài)機更新 (State Machine Update)?步驟中,當(dāng)控制器的狀態(tài)機進行流經(jīng) Exit 狀態(tài)的轉(zhuǎn)換時,將在最后一個更新幀上調(diào)用此回調(diào)。在轉(zhuǎn)換到?StateMachine?子狀態(tài)時不會調(diào)用此回調(diào)。
僅當(dāng)動畫圖中存在控制器組件(例如,AnimatorController、AnimatorOverrideController?或?AnimatorControllerPlayable)時才會發(fā)生此回調(diào)。
注意:將此回調(diào)添加到?StateMachineBehaviour?組件會禁用多線程的狀態(tài)機評估。觸發(fā)動畫事件 (Fire Animation Events):調(diào)用在上次更新時間和當(dāng)前更新時間之間采樣的所有剪輯中的所有動畫事件。
StateMachineBehaviour (OnStateEnter/OnStateUpdate/OnStateExit):一個層最多可以有 3 個活動狀態(tài):當(dāng)前狀態(tài)、中斷狀態(tài)和下一個狀態(tài)。使用一個定義?OnStateEnter、OnStateUpdate?或?OnStateExit?回調(diào)的 StateMachineBehaviour 組件為每個活動狀態(tài)調(diào)用此函數(shù)。
依次針對當(dāng)前狀態(tài)、中斷狀態(tài)和下一個狀態(tài)調(diào)用此函數(shù)。
僅當(dāng)動畫圖中存在控制器組件(例如,AnimatorController、AnimatorOverrideController?或?AnimatorControllerPlayable)時才會執(zhí)行此步驟。OnAnimatorMove:在每個更新幀中為每個 Animator 組件調(diào)用一次此函數(shù)來修改根運動 (Root Motion)。
StateMachineBehaviour(OnStateMove):使用定義此回調(diào)的?StateMachineBehaviour?在每個活動狀態(tài)中調(diào)用此函數(shù)。
OnAnimatorIK:設(shè)置動畫 IK。為每個啟用?IK pass?的 Animator Controller 層進行一次此調(diào)用。
僅當(dāng)使用人形骨架時才會執(zhí)行此事件。StateMachineBehaviour(OnStateIK):使用在啟用?IK pass?的層上定義此回調(diào)的?StateMachineBehaviour?組件在每個活動狀態(tài)中調(diào)用此函數(shù)。
WriteProperties:從主線程將所有其他動畫屬性寫入場景。
有用的性能分析標(biāo)記
腳本生命周期流程圖中顯示的某些動畫函數(shù)不是可以調(diào)用的事件函數(shù);它們是 Unity 處理動畫時調(diào)用的內(nèi)部函數(shù)。
這些函數(shù)具有 Profiler 標(biāo)記,因此您可以使用?Profiler?查看 Unity 在幀中調(diào)用這些函數(shù)的時間。知道 Unity 調(diào)用這些函數(shù)的時間有助于準(zhǔn)確了解所調(diào)用的事件函數(shù)的具體執(zhí)行時間。
例如,假設(shè)在?FireAnimationEvents?回調(diào)中調(diào)用?Animator.Play。如果知道只有在執(zhí)行狀態(tài)機更新 (State Machine Update)?和流程圖 (Process Graph)?函數(shù)后才會觸發(fā)?FireAnimationEvents?回調(diào),就可以預(yù)期動畫剪輯會在下一幀播放,而不是馬上播放。
狀態(tài)機更新 (State Machine Update):在執(zhí)行序列的此步驟中評估所有狀態(tài)機。僅當(dāng)動畫圖中存在控制器組件(例如,AnimatorController、AnimatorOverrideController?或?AnimatorControllerPlayable)時才會發(fā)生此回調(diào)。
注意:狀態(tài)機評估通常是多線程的,但添加某些回調(diào)(例如,OnStateMachineEnter?和?OnStateMachineExit)會禁用多線程。請參數(shù)上文的動畫更新循環(huán)以了解詳細信息。ProcessGraph:評估所有動畫圖。此過程包括對需要評估的所有動畫剪輯進行采樣以及計算根運動 (Root Motion)。
ProcessAnimation:混合動畫圖的結(jié)果。
WriteTransforms:將所有動畫變換從工作線程寫入場景。
如果一個人形骨架的多個層啟用了?IK pass,則該人形骨架可以有多個?WriteTransforms?通道(請參閱腳本生命周期流程圖)。
Rendering
OnPreCull:在攝像機剔除場景之前調(diào)用。剔除操作將確定攝像機可以看到哪些對象。正好在進行剔除之前調(diào)用 OnPreCull。
OnBecameVisible/OnBecameInvisible:對象變?yōu)閷θ魏螖z像機可見/不可見時調(diào)用。
OnWillRenderObject:如果對象可見,則為每個攝像機調(diào)用一次。
OnPreRender:在攝像機開始渲染場景之前調(diào)用。
OnRenderObject:所有常規(guī)場景渲染完成之后調(diào)用。此時,可以使用?GL?類或?Graphics.DrawMeshNow?來繪制自定義幾何形狀。
OnPostRender:在攝像機完成場景渲染后調(diào)用。
OnRenderImage:在場景渲染完成后調(diào)用以允許對圖像進行后處理,請參閱后期處理效果。
OnGUI:每幀調(diào)用多次以響應(yīng) GUI 事件。首先處理布局和重新繪制事件,然后為每個輸入事件處理布局和鍵盤/鼠標(biāo)事件。
OnDrawGizmos?用于在場景視圖中繪制輔助圖標(biāo)以實現(xiàn)可視化。
協(xié)程
Update 函數(shù)返回后將運行正常協(xié)程更新。協(xié)程是一個可暫停執(zhí)行 (yield) 直到給定的 YieldInstruction 達到完成狀態(tài)的函數(shù)。 協(xié)程的不同用法:
yield?在下一幀上調(diào)用所有 Update 函數(shù)后,協(xié)程將繼續(xù)。
yield WaitForSeconds?在為幀調(diào)用所有 Update 函數(shù)后,在指定的時間延遲后繼續(xù)協(xié)程
yield WaitForFixedUpdate?在所有腳本上調(diào)用所有 FixedUpdate 后繼續(xù)協(xié)程
yield WWW?在 WWW 下載完成后繼續(xù)。
yield StartCoroutine?將協(xié)程鏈接起來,并會等待 MyFunc 協(xié)程先完成。
銷毀對象時
OnDestroy:對象存在的最后一幀完成所有幀更新之后,調(diào)用此函數(shù)(可能應(yīng) Object.Destroy 要求或在場景關(guān)閉時銷毀該對象)。
退出時
在場景中的所有活動對象上調(diào)用以下函數(shù):
OnApplicationQuit:在退出應(yīng)用程序之前在所有游戲?qū)ο笊险{(diào)用此函數(shù)。在編輯器中,用戶停止播放模式時,調(diào)用函數(shù)。
OnDisable:行為被禁用或處于非活動狀態(tài)時,調(diào)用此函數(shù)。