三教杯專案問題1——關於Awake、Start執行順序的問題
緣由
剛接觸了一週Unity就匆匆忙忙參加了學校的一個一週限時遊戲開發的比賽,結果由於對Unity的不熟悉導致出現了各種奇奇怪怪的問題。本來計劃好的很多功能最終因為要解決冒出來的各種問題導致只實現了很小一部分。現在“作業”終於提交上去了,抽空來整理一下遇到的各種問題。
我做的是一個射擊型別的遊戲。既然是射擊型別的遊戲那肯定避免不了要使用物件池。然而奇怪的是,在遊戲開始之後雖然物件池內已經生成了預設體,但是Unity卻丟擲了找不到物件池中物件的問題。通過各種排查發現,原來是呼叫的時候物件池還沒有初始化,而產生這個問題的原因是把物件池的初始化語句放在了Start中導致的,把初始化語句挪到Awake中完美的解決了問題。那麼Unity中Awake、Start他們的執行和順序到底是怎樣的呢?
分析
檢視一下Unity官方的API吧。(以下是我自己翻譯的,僅供參考)
Awake()
當載入指令碼例項時呼叫Awake。
Awake被用來在遊戲開始前初始化任何變數或遊戲狀態。在指令碼的生命週期中只調用一次Awake。當所有物件被初始化之後呼叫Awake,因此你可以安全的讓其他物件使用例如GameObject.FindWithTag。每個GameObject的Awake的呼叫是隨機的。因此,你需要使用Awake建立指令碼之間的引用,使用Start來相互傳遞資訊。Awake總是在啟動任何函式之前被呼叫。這允許你對指令碼的初始化進行排序。Awake不能扮演coroutine的角色。
Start()
Start在指令碼啟用之後,第一次呼叫任何Update方法之前的幀呼叫。像Awake函式一樣,在指令碼的生命週期中只會呼叫一次Start。然而,無論指令碼是否啟用,當初始化指令碼物件時都會呼叫Awake函式。如果初始化時沒有啟動指令碼,Start可能不會和Awake在相同的幀上被呼叫。
在呼叫任何物件的Start之前,將會對場景中所有物件呼叫Awake函式。這在物件A的初始化程式碼需要依賴物件B已經初始化的情況下是非常有用的。B的初始化需要在Awake完成,而A的初始化需要在Start中完成。
當物件在遊戲過程中被例項化時,他們的Awake函式在場景物件的Start函式已經完成時啟動。
其實官方的API中說的已經很清楚了,所有物件初始化之後都會統一先呼叫Awake(這個呼叫順序是隨機的),在所有初始化物件的Awake呼叫都結束之後才會呼叫Start!因此我們需要在Awake中對物件進行必要的初始化,然後在Start中進行相互間的使用,否則極有可能會返回找不到物件的異常。