文章目錄
- 前言
- 1. Unity的生命周期
- 加載第一個場景
- Editor
- 在第一次幀更新之前
- 幀之間
- 更新順序
- 協程
- 銷毀對象時
- 退出時
- 2. Unity 協程和線程,進程的區別
- 3. 本地坐標系 世界坐標系
- 4. 碰撞器和觸發器的區別
- 后話
前言
開設這個欄目的博文會寫一些有關unity的面試題目,在面試的過程中,考官可能會問到的東西,雖然更多的是問有關項目經歷的,但是這些內容也會涉獵到。
1. Unity的生命周期
下圖是Unity官方給出的腳本生命周期流程圖。
加載第一個場景
場景開始時將調用以下函數(為場景中的每個對象調用一次)。
Awake:始終在任何 Start 函數之前并在實例化預制件之后調用此函數。(如果游戲對象在啟動期間處于非活動狀態,則在激活之后才會調用 Awake。)
OnEnable:(僅在對象處于激活狀態時調用)在啟用對象后立即調用此函數。在創建 MonoBehaviour 實例時(例如加載關卡或實例化具有腳本組件的游戲對象時)會執行此調用。
Editor
Reset:調用 Reset 可以在腳本首次附加到對象時以及使用 Reset 命令時初始化腳本的屬性。
OnValidate:每當設置腳本的屬性時都會調用 OnValidate,包括反序列化對象時,這可能發生在不同的時間,例如在編輯器中打開場景時和域重新加載后。
在第一次幀更新之前
Start:僅當啟用腳本實例后,才會在第一次幀更新之前調用 Start。
幀之間
OnApplicationPause:在幀的結尾處調用此函數(在正常幀更新之間有效檢測到暫停)。在調用 OnApplicationPause 之后,將發出一個額外幀,從而允許游戲顯示圖形來指示暫停狀態。
更新順序
跟蹤游戲邏輯和交互、動畫、攝像機位置等的時候,可以使用一些不同事件。常見方案是在 Update 函數中執行大多數任務,但是也可以使用其他函數。
FixedUpdate:調用 FixedUpdate 的頻度常常超過 Update。如果幀率很低,可以每幀調用該函數多次;如果幀率很高,可能在幀之間完全不調用該函數。在 FixedUpdate 之后將立即進行所有物理計算和更新。在 FixedUpdate 內應用運動計算時,無需將值乘以 Time.deltaTime。這是因為 FixedUpdate 的調用基于可靠的計時器(獨立于幀率)。
Update:每幀調用一次 Update。這是用于幀更新的主要函數。
LateUpdate:每幀調用一次 LateUpdate(在 Update 完成后)。LateUpdate 開始時,在 Update 中執行的所有計算便已完成。LateUpdate 的常見用途是跟隨第三人稱攝像機。如果在 Update 內讓角色移動和轉向,可以在 LateUpdate 中執行所有攝像機移動和旋轉計算。這樣可以確保角色在攝像機跟蹤其位置之前已完全移動。
通常,不應依賴為不同的游戲對象調用相同事件函數的順序 - 除非順序明確記錄或可設置。(如果需要對播放器循環進行更細粒度的控制,可以使用 PlayerLoop API。)
不能指定為同一 MonoBehaviour 子類的不同實例調用事件函數的順序。例如,一個 MonoBehaviour 的 Update 函數可能會在另一個游戲對象(包括其父級或子級游戲對象)上的相同 MonoBehaviour 的 Update 函數之前或之后調用。
可以指定一個 MonoBehaviour 子類的事件函數應在不同子類的事件函數之前調用(使用 Project Settings 窗口的 Script Execution Order 面板)。例如,如果有兩個腳本,EngineBehaviour 和 SteeringBehaviour,可以設置 Script Execution Order,這樣 EngineBehaviours 始終在 SteeringBehaviours 之前更新。
協程
Update 函數返回后將運行正常協程更新。協程是一個可暫停執行 (yield) 直到給定的 YieldInstruction 達到完成狀態的函數。 協程的不同用法:
yield 在下一幀上調用所有 Update 函數后,協程將繼續。
yield WaitForSeconds 在為幀調用所有 Update 函數后,在指定的時間延遲后繼續。
yield WaitForFixedUpdate 在所有腳本上調用所有 FixedUpdate 后繼續。如果協同程序在 FixedUpdate 之前生成,那么它會在當前幀的 FixedUpdate 之后繼續運行。
yield WWW 在 WWW 下載完成后繼續。
yield StartCoroutine 將協程鏈接起來,并會等待 MyFunc 協程先完成。
銷毀對象時
OnDestroy:對象存在的最后一幀完成所有幀更新之后,調用此函數(可能應 Object.Destroy 要求或在場景關閉時銷毀該對象)。
退出時
在場景中的所有活動對象上調用以下函數:
OnApplicationQuit:在退出應用程序之前在所有游戲對象上調用此函數。在編輯器中,用戶停止播放模式時,調用函數。
OnDisable:行為被禁用或處于非活動狀態時,調用此函數。
2. Unity 協程和線程,進程的區別
- 其實很簡單,首先需要理解進程和線程是怎么一回事:進程是Windows系統中的一個基本概念,他包含著運行一個程序所需要的基本資源。一個正在運行的應用程序在操作系統中被視為一個進程,進程可以包括一個或多個線程。
- 進程和線程的區別通過以上,一目了然。
- 再談談線程和協程的區別。一般應用一個應用程序只使用線程這一“資源”。
- 需要明確,Unity只使用了一個線程,但是,我們需要”同時做很多事“,那Unity作為單線程,該如何去做,協程,就來了,協程是一種”偽線程“。 協同程序(coroutine).,即協作式程序,一系列互相依賴的協程間依次使用CPU,每次只有一個協程工作,而其他協成處于休眠狀態。協程實際上是在一個線程中,只不過每個協程對CPU進行分時,協程可以訪問和使用unity的所有方法和component。
- 同一時間只能執行某個協程,協程適合對某個任務進行分時處理。
控制代碼在特定的時間執行。 - 協程不是線程,也不是異步執行,跟Update一樣,在主線程中執行。
- 不用考慮同步和鎖的問題。
- 協程是一個分部組件,遇到條件(yield return)會掛起,直到條件滿足才會被喚起執行后面的語句。
3. 本地坐標系 世界坐標系
- 世界坐標系:世界坐標是指物體在場景中的坐標,當某個物體沒有父物體時,它的position即為世界坐標的position,rotation同理;本地坐標是物體相對于它的父物體的坐標而言,這個相對坐標是以父物體本身為坐標軸進行計算的,與世界坐標沒有必然聯系。而對于沒有父物體的物體,可以認為不存在本地坐標這種說法。
- 本地坐標系:當某個物體有父物體時,它的inspector欄transform中的position實際是localposition,即本地坐標。
- 使用
TransformPoint
方法將本地坐標系轉為世界坐標系
4. 碰撞器和觸發器的區別
- 碰撞器是觸發器的載體,而觸發器只是碰撞器身上的一個屬性。
- 當Is Trigger=false時,碰撞器根據物理引擎引發碰撞,產生碰撞的效果,可以調用OnCollisionEnter/Stay/Exit函數;
- 當Is Trigger=true時,碰撞器被物理引擎所忽略,沒有碰撞效果,可以調用OnTriggerEnter/Stay/Exit函數。
- 如果既要檢測到物體的接觸又不想讓碰撞檢測影響物體移動或要檢測一個物件是否經過空間中的某個區域這時就可以用到觸發器
后話
有很多基礎的面試題你面試過,但是文中沒有提及的歡迎留言補充~
enjoy ~