discuz!cms
迈开腿让我看一下小鸡蛋视频,无码中文av波多野吉衣迅雷下载
匯寶盆 > 免費(fèi)分享區(qū) > CG教程 > Unity > Unity消息系統(tǒng)
Unity消息系統(tǒng)

最好一點(diǎn)涼光

資源數(shù):63個(gè)

目錄CONTENTS

一、Unity消息系統(tǒng)

在線預(yù)覽PREVIEW

Unity消息系統(tǒng)

Unity消息系統(tǒng)

Unity有個(gè)消息系統(tǒng),該系統(tǒng)用來(lái)實(shí)現(xiàn)游戲運(yùn)行時(shí)腳本內(nèi)部方法的調(diào)用。這是個(gè)非常簡(jiǎn)單和容易理解的概念,特別對(duì)新用戶來(lái)說(shuō)。只需定義一個(gè)Update方法,便可以每幀調(diào)用該方法中的內(nèi)容。

一個(gè)經(jīng)驗(yàn)豐富的開(kāi)發(fā)者肯定會(huì)對(duì)此產(chǎn)生疑問(wèn):
1.不清楚這個(gè)方法究竟是如何被調(diào)用的。
2.不清楚當(dāng)一個(gè)場(chǎng)景中有多個(gè)對(duì)象時(shí),這些方法是如何調(diào)用順序。
3.這種代碼風(fēng)格不是十分智能。
UPDATE是怎么被調(diào)用的Unity并沒(méi)有使用System.Reflection進(jìn)行方法的定位。
取而代之的是,首先給定類(lèi)型的MonoBehaviour通過(guò)底層腳本進(jìn)行檢查,判斷腳本運(yùn)行過(guò)程中(無(wú)論是Mono或IL2CPP)是否有方法被定義,同時(shí)其中內(nèi)容有沒(méi)有被緩存。如果檢查到特定的方法,便將其添加到一個(gè)合適的列表中。例如,當(dāng)一個(gè)腳本中定義了Update方法后,這個(gè)腳本便被添加至一個(gè)需要每幀更新的腳本列表中。
在游戲過(guò)程中,Unity只需要重復(fù)執(zhí)行所有列表中的方法既可。所以,你的Update方法究竟是public還是private并不重要。UPDATE方法們的執(zhí)行順序是什么執(zhí)行順序由腳本執(zhí)行順序設(shè)置(Script Execution Order Settings)(菜單:Edit > Project Settings > Script Execution Order)決定。要手動(dòng)設(shè)置1000個(gè)腳本的執(zhí)行順序不是什么好主意,但是要微調(diào)某些特定腳本的執(zhí)行順序還是可以的。當(dāng)然,未來(lái)我們將會(huì)提供更加方便的方式來(lái)指定執(zhí)行順序,比如在代碼中使用一個(gè)特性(Attribute)。無(wú)法使用INTELLISENSE在Unity中,我們使用某類(lèi)IDE編譯C#腳本,這些IDE大多無(wú)法識(shí)別這些特定方法應(yīng)該在何處被調(diào)用。因此常會(huì)導(dǎo)致警告以及玳瑁導(dǎo)航困難。
一些開(kāi)發(fā)者用一個(gè)叫BaseMonoBehaviour或差不多名字的抽象類(lèi)擴(kuò)展MonoBehaviour,然后在他們的項(xiàng)目中的每個(gè)腳本里都擴(kuò)展這個(gè)類(lèi)。他們?cè)谄渲袑?xiě)了一些有用的功能以及一堆虛的特殊方法:這個(gè)結(jié)構(gòu)可以使你在代碼中使用MonoBehaviour時(shí)更有邏輯性,但存在一個(gè)小缺點(diǎn)。我打賭你已經(jīng)發(fā)現(xiàn)了……
你所有的MonoBehaviour都會(huì)儲(chǔ)存在Unity的內(nèi)部更新列表里,你所有的腳本都會(huì)在每幀里調(diào)用所有這些基本上什么也沒(méi)用的方法!
有人可能會(huì)問(wèn)為什么會(huì)有人關(guān)心一個(gè)空方法?因?yàn)檫@些從C++到托管C#的調(diào)用有成本上的開(kāi)銷(xiāo)。讓我們來(lái)看看成本為何。調(diào)用10000個(gè)UPDATE我為這篇文章在Github上創(chuàng)建了一個(gè)示例項(xiàng)目,大家可以前往以下鏈接下載:
https://github.com/valyard/Unity-Updates
它有兩個(gè)場(chǎng)景,可以通過(guò)點(diǎn)擊設(shè)備或在編輯器中按任意鍵互相切換:
(1) 在第一個(gè)場(chǎng)景中,使用下面這樣的代碼創(chuàng)建了10000個(gè)MonoBehaviour:(2) 在第二個(gè)場(chǎng)景中,創(chuàng)建了另外10000個(gè)MonoBehaviour。不過(guò),不同的是,這個(gè)代碼中并不是只調(diào)用Update,而是像下面這樣,加入了一個(gè)由Manager腳本在每幀都調(diào)用一次的自定義UpdateMe方法。測(cè)試項(xiàng)目在兩臺(tái)iOS設(shè)備上被編譯為Mono以及IL2CPP,發(fā)布設(shè)置中都設(shè)為非開(kāi)發(fā)模式。它們的運(yùn)行時(shí)間記錄如下:
1.在第一次Update調(diào)用時(shí)設(shè)置一個(gè)Stopwatch (在Script Execution Order中配置)
2.在LateUpdate時(shí)停止Stopwatch
3.將獲得的計(jì)時(shí)時(shí)間均攤到幾分鐘上

Unity版本: 5.2.2f1
iOS版本: 9.0

Mono哇!好多時(shí)間!測(cè)試肯定哪里出了問(wèn)題!
實(shí)際上,我只是忘了把Script Call Optimization 設(shè)為Fast but no exceptions,但是現(xiàn)在我們能看到這種設(shè)置對(duì)性能的影響了……至于IL2CPP不必太在意。
Mono (fast but no exceptions)OK,這樣好多了,讓我們切換到IL2CPP。
IL2CPP這里我們發(fā)現(xiàn)兩件事情:
1.這個(gè)優(yōu)化對(duì)于IL2CPP同樣有用
2.IL2CPP仍有改進(jìn)空間,而且在寫(xiě)這篇文章的同時(shí)Scripting 與IL2CPP團(tuán)隊(duì)正在努力提高性能。比如,最新的Scripting分支內(nèi)包含的優(yōu)化可以讓測(cè)試運(yùn)行快35%。

我接下來(lái)就會(huì)介紹Unity在幕后做了些什么,但是現(xiàn)在讓我們修改下Manager代碼,將它提速5倍!接口調(diào)用,虛調(diào)用以及數(shù)組訪問(wèn)結(jié)果告訴我們,如果你想在每幀里都循環(huán)迭代擁有10000個(gè)元素的列表,那應(yīng)該使用數(shù)組而不是List,因?yàn)檫@樣生成的C++代碼會(huì)更簡(jiǎn)單,而數(shù)組訪問(wèn)就是要快很多的。
在下一個(gè)測(cè)試中,我把List<ManagedUpdateBehavior> 改為了ManagedUpdateBehavior[]。這看起來(lái)好多了!解救之道!我們發(fā)現(xiàn)了從C++調(diào)用C#函數(shù)較慢,不過(guò)讓我們?cè)傺芯肯庐?dāng)調(diào)用所有這些對(duì)象的Update方法時(shí),Unity實(shí)際上做了些什么。最簡(jiǎn)單的方法就是使用Apple Instruments的Time Profiler。
注意這不是Mono與IL2CPP 的對(duì)比測(cè)試 — 討論的大多數(shù)內(nèi)容對(duì)Mono iOS構(gòu)建同樣適用。
我在iPhone6上用Time Profiler啟動(dòng)了測(cè)試項(xiàng)目,記錄了幾分鐘的數(shù)據(jù),然后選擇了一分鐘檢視一次。從這行代碼開(kāi)始的所有東西我們都很感興趣:
void BaseBehaviourManager::CommonUpdate<BehaviourManager>()

如果你以前沒(méi)有使用過(guò)Instruments,右邊是按照?qǐng)?zhí)行時(shí)間排序的函數(shù),以及它們調(diào)用的其他函數(shù)。最左邊的列是以毫秒為單位的CPU時(shí)間,以及這些函數(shù)及其調(diào)用的函數(shù)所占的CPU時(shí)間百分比。左邊第二列是函數(shù)自己的執(zhí)行時(shí)間。注意,在這個(gè)實(shí)驗(yàn)中Unity并沒(méi)有將CPU使用完,所以我們能看到在60秒間隔內(nèi)有10秒的CPU時(shí)間花在了我們的Update上。顯然,我們關(guān)心的是那些執(zhí)行時(shí)間最長(zhǎng)的函數(shù)。
用瘋狂的Photoshop技術(shù),將一些區(qū)域做了顏色區(qū)分,以便你能明白到底發(fā)生了什么。
UpdateBehavior.Update()
在中間你能看到我們的Update方法,以及IL2CPP是如何調(diào)用它的 ——UpdateBehavior_Update_m18。但是Unity在那之前還做了很多其他事。
循環(huán)迭代所有的Behaviour
Unity循環(huán)迭代所有的Behaviour并執(zhí)行更新。特殊的迭代類(lèi)SafeIterator確保了即使移除了列表中的下一項(xiàng),整個(gè)循環(huán)也不會(huì)中斷。僅僅是循環(huán)迭代所有已注冊(cè)的Behaviour就用了9979ms中的1517ms。
檢測(cè)調(diào)用是否有效
下一步,Unity做了一堆檢測(cè),確保調(diào)用的方法是屬于某個(gè)已激活已初始化且Start方法已調(diào)用過(guò)的GameObject的。你肯定不希望在Update里銷(xiāo)毀一個(gè)GameObject時(shí)讓游戲崩潰,對(duì)吧?這些檢測(cè)花去了整個(gè)9979ms中的另外2188ms。
準(zhǔn)備調(diào)用方法
Unity創(chuàng)建了一個(gè)ScriptingInvocationNoArgs實(shí)例 (代表了一個(gè)從原生到托管的調(diào)用)以及ScriptingArguments,然后命令I(lǐng)L2CPP虛擬機(jī)調(diào)用方法(scripting_method_invoke函數(shù))。這一步消耗了整個(gè)9979ms中的2061ms。
調(diào)用方法
scripting_method_invoke函數(shù)檢測(cè)傳入的參數(shù)是否有效(900ms),然后調(diào)用IL2CPP 虛擬機(jī)的Runtime::Invoke方法 (1520ms)。開(kāi)始時(shí),Runtime::Invoke檢測(cè)方法是否存在 (1018ms)。而后,它調(diào)用一個(gè)生成的RuntimeInvoker函數(shù)獲取方法簽名(283ms)。接著再依次調(diào)用我們的Update函數(shù),根據(jù)Time Profiler,這一步花了42ms。
一個(gè)漂亮的彩色表格。托管的更新現(xiàn)在讓那個(gè)我們?cè)?/span>Manager測(cè)試上使用下Time Profiler。你在屏幕截圖上可以看到,還是同樣的一些方法(有些方法因?yàn)閳?zhí)行時(shí)間少于1ms,甚至都沒(méi)出現(xiàn)),但是大部分的執(zhí)行時(shí)間實(shí)際上都花在了UpdateMe函數(shù)上(或者說(shuō)花在了IL2CPP調(diào)用ManagedUpdateBehavior_UpdateMe_m14上)。另外,IL2CPP還插入了一個(gè)null檢測(cè),確保我們循環(huán)迭代的數(shù)組不會(huì)為null。
下面這個(gè)圖片使用了相同的顏色。所以,你現(xiàn)在怎么看,我們應(yīng)該忽略那小小的方法調(diào)用嗎?有關(guān)測(cè)試的幾句話老實(shí)說(shuō),這個(gè)測(cè)試并不是完全公平的。Unity為了防止你的游戲出錯(cuò)或崩潰,做了很多了不起的事:這個(gè)GameObject是否已激活?它是否在Update循環(huán)中被銷(xiāo)毀了?對(duì)象上是否存在Update方法?怎么處理在這個(gè)Update循環(huán)中創(chuàng)建的MonoBehaviour?——我的Manager腳本沒(méi)有處理這其中任何一項(xiàng),僅僅是循環(huán)迭代了一堆的對(duì)象,調(diào)用它們的Update而已。
在真實(shí)世界中,Manager腳本可能會(huì)更加復(fù)雜,執(zhí)行得更慢。但是,我是個(gè)開(kāi)發(fā)者——我知道我的代碼要做什么,我架構(gòu)我的Manger類(lèi)時(shí),知道可能的行為是什么,什么不會(huì)出現(xiàn)在我的游戲中。而不幸的是,Unity并不知道這些。你應(yīng)該怎么做?當(dāng)然這完全視你的項(xiàng)目而定,但實(shí)戰(zhàn)中碰到一個(gè)游戲在單一場(chǎng)景中使用大量需要在每幀都執(zhí)行一些代碼的GameObject的情況并不少見(jiàn)。通常這看起來(lái)都是些不起眼的小代碼,似乎不會(huì)影響到任何東西,但當(dāng)其數(shù)量非常巨大時(shí),調(diào)用幾千個(gè)Update方法的開(kāi)銷(xiāo)將變得顯著。這個(gè)時(shí)候再去修改游戲架構(gòu),重構(gòu)這些對(duì)象為Manager樣式,可能已經(jīng)為時(shí)已晚。
你現(xiàn)在有數(shù)據(jù)了,在你開(kāi)始下一個(gè)項(xiàng)目時(shí)考慮下吧。


預(yù)覽結(jié)束,完整教程請(qǐng) 購(gòu)買(mǎi)下載
資源參數(shù)
    教程名稱:Unity消息系統(tǒng) 語(yǔ)       言:中文 頁(yè)數(shù)/時(shí)長(zhǎng): 3頁(yè)
    軟件版本: unity 上傳時(shí)間:2018/02/27 價(jià)格:¥0
    文件格式: docx 文件大?。?7kb
下載

使用說(shuō)明:

1. 本站所有資源(包括3D模型、CG教程、插件軟件、材質(zhì)貼圖、工程文件等)由設(shè)計(jì)師上傳,僅供學(xué)習(xí)、參考,請(qǐng)勿用于非法用途。

2. 本站付費(fèi)類(lèi)資源第一次需有償下載,重復(fù)下載不再收費(fèi)。

3. 若出現(xiàn)3d模型類(lèi)資源打不開(kāi),請(qǐng)確認(rèn)您的軟件版本是否過(guò)低。

4. 本站歡迎設(shè)計(jì)師注冊(cè)開(kāi)店,上傳作品進(jìn)行交流、交易。

5. 如在使用過(guò)程中,遇到任何問(wèn)題,請(qǐng)下拉頁(yè)面至評(píng)論區(qū)留言,或咨詢QQ:2353487910。

關(guān)鍵詞: Unity

您還未登錄

全部評(píng)論: 0