Unity中調用Awake,Start,Update等方法的原理機制


首先聲明這里的理解並不是官方釋義,只是舶主根據晚上的各位大佬的關點理解總結的,如果有什么不對的地方希望大家指正:

作為Unity中的生命周期准確的鬧明白它的實現原理還是很重要的我認為。生命周期方法的實現機制實際上是一種類反射機制。Uniy引擎整體是架設在mono IDE基礎上的。mono IDE是支持通過string來查找方法的,且和真正的反射一樣是能夠查找調用私有方法的,當找到這些方法后會存下指針,待使用。在引擎內部存在一張表,這張表的形成是通過在場景中查找全部的MonoBehaviour

類型腳本然后便利里面的方法,將需要的調用的方法是全部記錄下來,然后進行調用。防止那些不需要調用的MonoBehaviour中的方法占用空間,節省資源開耗。Mono的API可能效率更高,但對於單次調用,性能仍然遜於虛方法調用。反射實際上是開銷非常大的調用方式,比之虛方法來說要高得多,因此Unity選擇使用反射並非是出於性能方面的考慮。實際上,每幀調用的這些事件方法從數量級上來說是很卑微的,反射造成的性能影響亦可忽略不計。

 Unity使用這種事件機制的根本原因是出於對靈活性的考慮。Unity采用組件式設計,觸發一個事件,需要通知到相應gameobject的所有組件。如果使用多態來實現,則必須假設所有組件都派生自包含此事件的基類,或者篩選出派生自此基類的組件逐一通知。這樣一來是麻煩,二來則容易帶來復雜的繼承關系,與組件式這種倡導用聚合代替繼承的設計從理念上就是相悖的。
另一方面的原因則是為了跟JS保持一致性。這種事件機制對於JS這種動態類型語言來說是渾然天成的。
這種設計最大的缺陷在於事件名通過字符串耦合,如此一來,完全繞開了編譯期靜態檢查,無法為事件調用的正確性提供保障;在復雜的系統里,也可能因為事件重名而導致bug。
 

Unity的確是通過反射來調用腳本的方法的,並且這一過程會在運行時不停對所有MonoBehaviour遍歷進行。

Unity之所以統一地使用這一套固定的函數命名方案,便於明確地划出了每個函數需要做些什么。這樣做的目的我猜測是有利用保留腳本的靈活性。這種做法被慣稱為“事件機制”,一旦某個腳本被執行完成之后,它的控制權會重新回到調度管理處,可以輕松地再去執行下一個,並且也能在運行時通過反射方式讓其它腳本使用Component.SendMessage進行調用。

如果采用了抽象方式讓子類去實現這樣的方法,那么對於Unity本身的對象管理是沒有任何好處的,並且對於擁有多個腳本組件的對象來說,維護成本不但增加了,還可能讓腳本之間的管理變得混亂。

使用反射也許會丟失一些性能,但卻能讓每個不同的MonoBehaviour之間看起來都是獨立的,只需要在它提供的幾個內置方法中關注自己的邏輯就可以了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM