如今越來(lái)越多的開(kāi)發(fā)者使用Unity開(kāi)發(fā)Android及iOS項(xiàng)目,開(kāi)發(fā)過(guò)程中難免會(huì)遇到一些性能方面的問(wèn)題,例如掉幀、延遲和卡頓等等颗胡,導(dǎo)致游戲體驗(yàn)變差甚至毫無(wú)游戲體驗(yàn)可言。今天這篇文章將由Niels Tiercelin吩坝,為大家深入剖析Unity項(xiàng)目?jī)?yōu)化過(guò)程毒姨。
游戲性能分析
Unity Profiler
建議使用Unity Profiler工具(Window > Profiler)來(lái)分析項(xiàng)目性能,該工具以圖形化的方式呈現(xiàn)游戲具體的行為钉寝、計(jì)算所需的時(shí)間以及每幀渲染的時(shí)長(zhǎng)等等弧呐,包含所有可能會(huì)影響性能的數(shù)據(jù)鸳址。使用該工具非常簡(jiǎn)單,只需點(diǎn)擊圖表本身(例如點(diǎn)擊圖表中的某個(gè)高峰)就可以查看該幀的詳細(xì)計(jì)算數(shù)據(jù)泉懦。Unity會(huì)顯示耗時(shí)最長(zhǎng)的處理步驟。如果并不理解其中某個(gè)處理步驟的意義疹瘦,也很容易在網(wǎng)上搜索來(lái)查找相關(guān)內(nèi)容崩哩。
Unity Profiler 本身在編輯器環(huán)境下運(yùn)行,并展示游戲運(yùn)行的細(xì)節(jié)言沐,但請(qǐng)注意邓嘹,這里并不能反映出游戲的真實(shí)性能。由于Unity編輯器需要處理游戲本身以及額外的內(nèi)容险胰,因此此時(shí)的游戲運(yùn)行速度會(huì)比構(gòu)建之后的游戲慢一些汹押。
Remote Profiler
使用Unity Profiler無(wú)法得知游戲運(yùn)行的真實(shí)性能,所以需要在設(shè)備上運(yùn)行游戲并進(jìn)行分析起便。下面以Android設(shè)備為例棚贾,配置Android SDK和JDK后構(gòu)建項(xiàng)目,然后就可以開(kāi)始使用Remote Profiler了榆综。在Build Settings中(File > Build Settings)同時(shí)勾選 “Development Build” 和 “Autoconnect Profiler”妙痹,并確保 Editor Settings 設(shè)置中的 “Device” 一欄為 “Any Android Device”。
選擇設(shè)備作為“Active Profiler”
編輯器日志
另一種獲取信息的方式是編輯器日志中燥。游戲構(gòu)建完畢后立刻打開(kāi)Console窗口(Window > Console)寇甸,在窗口的右上方有一個(gè)按鈕,點(diǎn)擊后選擇 “Open Editor Log”疗涉。此時(shí)系統(tǒng)會(huì)打開(kāi)一個(gè)文檔拿霉,其中包含很多構(gòu)建相關(guān)的信息,特別是構(gòu)建文件的大小以及資源占據(jù)的空間等咱扣。
在不同設(shè)備上進(jìn)行測(cè)試
Android開(kāi)發(fā)相當(dāng)復(fù)雜绽淘,可能會(huì)出現(xiàn)很多問(wèn)題。因?yàn)槟硞€(gè)性能問(wèn)題可能僅在某些設(shè)備上出現(xiàn)闹伪,而在另外一些設(shè)備上完全不是問(wèn)題沪铭。因此應(yīng)該在不同設(shè)備上測(cè)試游戲壮池,從而避免此類問(wèn)題,保證您的游戲能夠在絕大多數(shù)設(shè)備上正常運(yùn)行杀怠。雖然等到項(xiàng)目開(kāi)發(fā)后期再做優(yōu)化這種想法很常見(jiàn)椰憋,但此時(shí)的性能問(wèn)題可能已堆積成山。因此最好的做法是周期性地檢測(cè)游戲赔退,例如在每個(gè)里程碑達(dá)成時(shí)進(jìn)行性能分析橙依。這樣隨著游戲不斷修改,需要進(jìn)行的優(yōu)化工作也會(huì)越來(lái)越少硕旗,也能越來(lái)越快地找到性能瓶頸所在窗骑。
腳本
搞定渲染優(yōu)化這個(gè)大目標(biāo)之前,應(yīng)該先保證腳本不會(huì)出現(xiàn)問(wèn)題漆枚。如果您是程序員创译,最好在把鍋甩給美術(shù)之前先檢查一下腳本是否有性能問(wèn)題(哪怕真的是美術(shù)的鍋!)
慎用Update
Unity初學(xué)者通常最大的誤解在于過(guò)于依賴Update()函數(shù)墙基。將所有內(nèi)容都塞到Update()中確實(shí)是最容易的做法软族,例如檢查某個(gè)狀態(tài)并根據(jù)狀態(tài)做出相應(yīng)動(dòng)作等,但如果場(chǎng)景中的每個(gè)GameObject都要在Update()里檢查非常多的東西或進(jìn)行復(fù)雜操作碘橘,就會(huì)大大影響游戲性能互订。所以,在使用Update()之前痘拆,首先問(wèn)一問(wèn)自己仰禽,要實(shí)現(xiàn)的功能真的需要逐幀運(yùn)行嗎?
使用協(xié)程
如果不是必須逐幀運(yùn)行纺蛆,還可選擇其他幾種方式來(lái)實(shí)現(xiàn)吐葵。例如,可以利用協(xié)程(Coroutines)讓某個(gè)方法每秒鐘運(yùn)行一次:“yield return new WaitForSeconds (1);”
可以用下面的方法刷新UI:
善用Events温峭、Actions,響應(yīng)式編程(Reactive Programming)字支。調(diào)用方法真正高效地方式是僅在需要時(shí)調(diào)用凤藏。例如當(dāng)某個(gè)變量改變時(shí)、某個(gè)方法被調(diào)用時(shí)堕伪,或者某個(gè)事件發(fā)生并彈出UI菜單時(shí)等等揖庄。這就是響應(yīng)式編程的基本原理,即利用Events欠雌,對(duì)某個(gè)事件作出反應(yīng)蹄梢。在C#中您可以使用委托,尤其是Action委托富俄,來(lái)創(chuàng)建事件禁炒。當(dāng)事件發(fā)生時(shí)調(diào)用某個(gè)函數(shù)而咆,然后由該函數(shù)去調(diào)用訂閱了該事件的方法。例如幕袱,創(chuàng)建 “玩家跳躍”事件暴备,在代碼中每當(dāng)玩家跳躍時(shí)就會(huì)發(fā)起這個(gè)事件。例如某個(gè)方法生成了一些灰塵效果或者播放跳躍音效们豌,將該方法訂閱到“玩家跳躍”這個(gè)事件上馍驯,玩家跳起來(lái)時(shí)就會(huì)調(diào)用生成灰塵效果播放音效的方法。這僅僅是一種簡(jiǎn)單的應(yīng)用玛痊,您還可以深入探究。如果您對(duì)響應(yīng)式編程有興趣狂打,可以參考UniRx - Reactive Extensions插件擂煞。這是為Unity設(shè)計(jì)的響應(yīng)式編程拓展,支持LINQ異步及多線程趴乡、LINQ訂閱到事件等等对省。
利用射線檢測(cè)可觸摸GameObject
在Unity中,除了UI之外并沒(méi)有什么比較容易的辦法來(lái)檢測(cè)某個(gè)GameObject在屏幕上的點(diǎn)擊晾捏。OnMouseDown() 函數(shù)對(duì)于移動(dòng)平臺(tái)并不生效蒿涎。一種可行的方案是使用射線。從攝像機(jī)出發(fā)惦辛,以屏幕上手指點(diǎn)擊的位置為方向劳秋。如果射線檢測(cè)到某個(gè)對(duì)象則調(diào)用該對(duì)象的方法∨制耄可以先定義一個(gè)Touchable類玻淑,一個(gè)Touchable層。觸摸到某個(gè)對(duì)象時(shí)則調(diào)用下面的方法:
如果檢測(cè)到觸摸操作作用在帶有Touchable的游戲?qū)ο笊涎交铮瑒t調(diào)用該對(duì)象的OnTouchDown()方法补履。
物理
檢查腳本時(shí)一定要檢查物理交互相關(guān)的代碼(如果存在)。當(dāng)然剿另,移動(dòng)設(shè)備上最好不要有此類代碼箫锤,但如果無(wú)法避免,應(yīng)特別注意以下幾點(diǎn):動(dòng)態(tài)剛體(Rigidbody)的數(shù)量越少越好雨女,它們會(huì)大量消耗計(jì)算性能罢低。使用基礎(chǔ)碰撞體,避免使用網(wǎng)格碰撞體偿洁,后者的計(jì)算處理要復(fù)雜得多屡江。盡量將“Collision Detection Mode” 設(shè)置為 “Discrete”,因?yàn)?“Continue” 會(huì)用掉更多的性能岔擂。最后位喂,可以在TimeManager窗口(Edit > Project Settings > Time)中設(shè)置 “Fixed Timestep” 的值(值越小物理計(jì)算越頻繁)浪耘。這個(gè)值表示兩次FixedUpdate()調(diào)用之間的時(shí)間間隔。
所以Fixed Timestep值越小表示函數(shù)調(diào)用越頻繁塑崖,從而獲得更精確的模擬計(jì)算結(jié)果七冲,代價(jià)則是消耗更多的資源。反之规婆,該值越大越能降低處理物理相關(guān)數(shù)據(jù)所占用的時(shí)間澜躺,如果不需要特別精確的計(jì)算結(jié)果這也是一個(gè)很好的選擇。