前言:記錄了總6w字的面經(jīng)知識點,文章中的知識點若想深入了解,可以點擊鏈接學習。由于文本太多,按類型分開。這一篇是 Unity 常問問題總結(jié),有幫助的可以收藏。?
1. 生命周期
????????Awake?—>?OnEnable —>?Start?—>?FixedUpdate?—>Update??—>?LateUpdate—>?OnGUl?—>?OnDisable?—>?OnDestroy
詳細介紹
????????1. Awake
????????Awake用于在游戲開始之前初始化變量或游戲狀態(tài)。在腳本整個生命周期內(nèi)它僅被調(diào)用一次,Awake在所有對象被初始化之后調(diào)用,
????????當腳本設(shè)置為不可用時,運行時Awake方法仍然會執(zhí)行一次。
????????所以你可以安全的與其他對象對話或用諸如GameObject.FindWithTag 這樣的函數(shù)搜索它們。每個游戲物體上的Awake以隨機的順序被調(diào)用。因此,你應(yīng)該用Awake來設(shè)置腳本間的引用,并用Start來傳遞信息,Awake總是在Start之前被調(diào)用。它不能用來執(zhí)行協(xié)同程序。
????????2.?OnEnable
????????當對象變?yōu)榭捎没蚣せ顮顟B(tài)時被調(diào)用事件監(jiān)聽。
????????3.?Start
????????Start在behaviour的生命周期中只被調(diào)用一次。它和Awake的不同是Start只在腳本實例被啟用時調(diào)用。你可以按需調(diào)整延遲初始化代碼。Start總是在Awake之后執(zhí)行。這允許你協(xié)調(diào)初始化順序。
????????4. Update
????????Update每幀調(diào)用一次用于更新游戲場景和狀態(tài),比較適合做控制。
????????5.?FixedUpdate
????????每隔固定物理時間間隔調(diào)用一次用于物理狀態(tài)的更新,和Update不同的是FixedUpdate邏輯幀,Update是渲染幀。如果幀率很低,可以每幀調(diào)用該函數(shù)多次;如果幀率很高,可能在幀之間完全不調(diào)用該函數(shù)。
????????FixedUpdate?內(nèi)應(yīng)用運動計算時,無需將值乘以?Time.deltaTime。這是因為?FixedUpdate?的調(diào)用基于可靠的計時器(獨立于幀率)。
????????詳細請看:FixedUpdate真的是固定的時間間隔執(zhí)行嗎?聊聊游戲定時器 - 慕容小匹夫 - 博客園0x00 前言 有時候即便是官方的文檔手冊也會讓人產(chǎn)生誤解,比如本文將要討論的Unity引擎中的FixedUpdate方法。 This function is called every fixed fhttps://www.cnblogs.com/murongxiaopifu/p/7683140.html
????????6. LateUpdate
????????每幀調(diào)用一次(在 update 之后調(diào)用) 用于更新游戲場景和狀態(tài),和攝像機相關(guān)的更新。
????????官網(wǎng)上例子是攝像機的跟隨,都是所有的Update操作完才進行攝像機的跟進,不然就有可能出現(xiàn)攝像機已經(jīng)推進了,但是視角里還未有角色的空幀出現(xiàn)。
????????7.?OnGUI
????????OnGUI 渲染和處理 OnGUI 事件。
????????8.?OnDisable
????????OnDisable 當對象變?yōu)椴豢捎没蚍羌せ顮顟B(tài)時被調(diào)用事件移除。
????????9.?OnDestroy
????????OnDestroy 當對象被銷毀時調(diào)用。
2. 如何讓已經(jīng)存在的GameObject在LoadLevel后不被卸載掉
????????DontDestroyOnLoad(transform.gameObject);
3. 碰撞
? ? ?物體發(fā)生碰撞的必要條件
????????兩個物體都必須帶有碰撞器Collider,其中一個物體還必須帶有Rigidbody剛體。
? ? ?碰撞器與觸發(fā)器
????????1.碰撞器是觸發(fā)器的載體,而觸發(fā)器只是碰撞器身上的一個屬性。
????????2. 當ls Trigger=false時,碰撞器根據(jù)物理引擎引發(fā)碰撞,產(chǎn)生碰撞的效果,可以調(diào)用OnCollisionEnter/Stay/Exit函數(shù);
????????3.當ls Trigger=true時,碰撞器被物理引擎所忽略,沒有碰撞效果,可以調(diào)用OnTriggerEnter/Stay/lExit函數(shù)。
????????4. 如果既要檢測到物體的接觸,又不想讓碰撞檢測影響物體移動或要檢測一個物件是否經(jīng)過空間中的某個區(qū)域,這時就可以用到觸發(fā)器。
4. 協(xié)程(進程/線程)
?????1. 概念
? ? 進程
????????保存在硬盤上的程序運行以后,會在內(nèi)存空間里形成一個獨立的內(nèi)存體,這個內(nèi)存體有自己獨立的地址空間,有自己的堆,不同進程間可以進行進程間通信,上級掛靠單位是操作系統(tǒng)。一個應(yīng)用程序相當于一個進程,操作系統(tǒng)會以進程為單位,分配系統(tǒng)資源(CPU 時間片、內(nèi)存等資源),進程是資源分配的最小單位。
? ? 線程
????????線程從屬于進程,也被稱為輕量級進程,是程序的實際執(zhí)行者。線程是操作系統(tǒng)能夠進行運算調(diào)度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以并發(fā)多個線程,每條線程并行執(zhí)行不同的任務(wù)。一個線程只有一個進程。
????????每個獨立的線程有一個程序運行的入口、順序執(zhí)行序列和程序的出口,但是線程不能夠獨立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個線程執(zhí)行控制。
????????線程擁有自己獨立的棧和共享的堆,共享堆,不共享棧,線程亦由操作系統(tǒng)調(diào)度(標準線程是的)。
? ? 協(xié)程
????????協(xié)程是伴隨著主線程一起運行的一段程序。
? ? 注意點:
????????協(xié)程與協(xié)程之間是并行執(zhí)行,與主線程也是并行執(zhí)行,同一時間只能執(zhí)行一個協(xié)程提起協(xié)程,自然是要想到線程,因為協(xié)程的定義就是伴隨主線程來運行的!
????????一個線程可以擁有多個協(xié)程,協(xié)程不是被操作系統(tǒng)內(nèi)核所管理,而完全是由程序所控制。
????????協(xié)程和線程一樣共享堆,不共享棧,協(xié)程由程序員在協(xié)程的代碼里顯示調(diào)度。
????????協(xié)成是單線程下由應(yīng)用程序級別實現(xiàn)的并發(fā)。
????????2.線程與協(xié)程的區(qū)別
????????協(xié)同程序與多線程情況下的線程比較類似:有自己的堆棧,自己的局部變量,有自己的指令指針,但與其它協(xié)同程序共享全局變量等很多信息。
????????協(xié)程(協(xié)同程序): 同一時間只能執(zhí)行某個協(xié)程。開辟多個協(xié)程開銷不大。協(xié)程適合對某任務(wù)進行分時處理。
????????線程: 同一時間可以同時執(zhí)行多個線程。開辟多條線程開銷很大。線程適合多任務(wù)同時處理。
????????1.協(xié)程,即協(xié)作式程序,其思想是,一系列互相依賴的協(xié)程間依次使用CPU,每次只有一個協(xié)程工作,而其他協(xié)程處于休眠狀態(tài)。協(xié)程實際上是在一個線程中,只不過每個協(xié)程對CPU進行分時,協(xié)程可以訪問和使用unity的所有方法和component。
????????2.線程,多線程是阻塞式的,每個IO都必須開啟一個新的線程,但是對于多CPU的系統(tǒng)應(yīng)該使用thread,尤其是有大量數(shù)據(jù)運算的時刻,但是IO密集型就不適合;而且thread中不能操作unity的很多方法和component。
????????線程和協(xié)同程序的主要不同在于:在多處理器情況下,從概念上來講多線程程序同時運行多個線程;而協(xié)同程序是通過協(xié)作來完成,在任一指定時刻只有一個協(xié)同程序在運行,并且這個正在運行的協(xié)同程序只在必要時才會被掛起。
?????2. 協(xié)程作用
????????在Unity中只有主線程才能訪問Unity3D的對象、方法、組件。當主線程在執(zhí)行一個對資源消耗很大的操作時,在這一幀我們的程序就會出現(xiàn)幀率下降,畫面卡頓的現(xiàn)象!
????????那這個時候我們就可以利用協(xié)程來做這件事,因為協(xié)程是伴隨著主線程運行的,主線程依舊可以絲滑輕松的工作,把臟活累活交給協(xié)程處理就好了!簡單來說:協(xié)程是輔助主線程的操作,避免游戲卡頓。
????????3.?操作
????????3.1定義協(xié)程
???IEnumerator Test(string str)
????{
????????//代碼塊
????????Debug.Log("協(xié)程被啟動了!"+ str);
????????yield return null;
????????//代碼塊
????}
????????3.2 啟動協(xié)程
????????1. Startcoroutine (string methodName):通過協(xié)程的方法名(字符串形式)啟動。
????????2. StartCoroutine (string methodName,object values):帶參數(shù)的通過方法名(字符串形式)進行調(diào)用。
????????3. Startcoroutine (IEnumerator routine):通過調(diào)用方法的形式啟動。
?????
?3.3 停止攜程
????????1.stopcoroutine (string methodName):通過方法名(字符串)來關(guān)閉協(xié)程。
????????2.stopCoroutine(IEnumerator routine):通過調(diào)用方法的形式來關(guān)閉協(xié)程。
????????3.stopCoroutine(Coroutine routine):通過指定的協(xié)程來關(guān)閉。
????????4.stopAllCoroutine() 的作用是停止所有該腳本中啟動的協(xié)程。
void StopTest()
????{
????????//第一種方式:通過調(diào)用方法的形式來關(guān)閉協(xié)程
????????StopCoroutine(Test1());
????????//第二種方式:通過方法名(字符串)來關(guān)閉協(xié)程
????????StopCoroutine("Test1");
????????//第三種方式:通過指定的協(xié)程來關(guān)閉
????????Coroutine a = StartCoroutine(Test1());
????????StopCoroutine(a);
????????//關(guān)閉該腳本中啟動的所有協(xié)程!
????????StopAllCoroutines();
????}
????????4. 底層原理
????????協(xié)程是通過迭代器來實現(xiàn)功能的,通過關(guān)鍵字IEnumerator來定義一個迭代方法。
????????注意:提起IEnumerator就會想到IEnumerable,可千萬不能搞混了!
????????StartCoroutine 接受到的是一個 IEnumerator ,這是個接口,并且是枚舉器或迭代器的意思。
????????yield 是 C#的一個關(guān)鍵字,也是一個語法糖,背后的原理會生成一個類,并且也是一個枚舉器,而且不同于 return,yield 可以出現(xiàn)多次。
????????yield 實際上就是返回一次結(jié)果,因為我們要一次一次枚舉一個值出來,所以多個 yield 其實是個狀態(tài)模式,第一個 yield 是狀態(tài) 1,第二個 yield 是狀態(tài) 2,每次訪問時會基于狀態(tài)知道當前應(yīng)該執(zhí)行哪一個 yield,取得哪一個值。
????????從程序的角度講,協(xié)程的核心就是迭代器。想要定義一個協(xié)程方法有兩個因素,第一:方法的返回值為 IEnumerator 。第二,方法中有 yield關(guān)鍵字。當代碼滿足以上兩個條件時,此方法的執(zhí)行就具有了迭代器的特質(zhì),其核心就是 MoveNext方法。方法內(nèi)的內(nèi)容將會被分成兩部分:yield 之前的代碼和 yield 之后的代碼。yield之前的代碼會在第一次執(zhí)行MoveNext時執(zhí)行, yield之后的代碼會在第二次執(zhí)行MoveNext方法時執(zhí)行。而在Unity中,MoveNext的執(zhí)行時機是以幀為單位的,無論你是設(shè)置了延遲時間,還是通過按鈕調(diào)用MoveNext,亦或是根本沒有設(shè)置執(zhí)行條件,Unity都會在每一幀的生命周期中判斷當前幀是否滿足當前協(xié)程所定義的條件,一旦滿足,當前幀就會抽出CPU時間執(zhí)行你所定義的協(xié)程迭代器的MoveNext。注意,只要方法中有yield語句,那么方法的返回值就必須是 IEnumerator ,不然無法通過編譯。
????????詳細請看:
https://blog.csdn.net/xiaoyaoACi/article/details/119957547?csdn_share_tail=%7B"type"%3A"blog"%2C"rType"%3A"article"%2C"rId"%3A"119957547"%2C"source"%3A"qq_35787977"%7Dhttps://blog.csdn.net/xiaoyaoACi/article/details/119957547?csdn_share_tail=%7B:,:,:,:%7D
????????測試:
????????解釋:a:Start函數(shù)正常運行
? ? ? ? ? ? ? ? ? ?b:Update函數(shù)正常運行
? ? ? ? ? ? ? ? ? ?c: 進入?yún)f(xié)程
? ? ? ? ? ? ? ? ? ?d:協(xié)程掛起,正常運行Update函數(shù)
? ? ? ? ? ? ? ? ? ?b:Update函數(shù)正常運行
? ? ? ? ? ? ? ? ? ?c: 進入?yún)f(xié)程
? ? ? ? ? ? ? ? ? ?d:協(xié)程掛起,正常運行Update函數(shù)
? ? ? ? ? ? ? ? ? ?e: ?因為協(xié)程是yield return null等待一幀后,第一幀的協(xié)程由掛起,變成正常運行,輸出e。
5. Invoke與InvokeRepeating
????1. Invoke
????????Invoke() 方法是?Unity3D?的一種委托機制文章來源:http://www.zghlxwxcb.cn/news/detail-783945.html
????????如: Invoke("Test", 5); ? 它的意思是:5 秒之后調(diào)用 Test() 方法;文章來源地址http://www.zghlxwxcb.cn/news/detail-783945.html
到了這里,關(guān)于Unity游戲開發(fā)客戶端面經(jīng)——Unity(初級)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!