一、 為什么要做性能優(yōu)化安岂?
性能:是一種優(yōu)秀的能力。喚醒快帆吻、運行持久域那、穩(wěn)定。
這種能力在游戲上能讓你的用戶感覺很爽猜煮,表征表現(xiàn)為加載快次员,手機不發(fā)熱,運行流暢王带,不卡頓淑蔚。所以,性能優(yōu)化的終極目標是愕撰,讓你的用戶感覺很爽刹衫,當然這種爽你不能以犧牲自己為代價醋寝,要考慮成本和副作用(總不能頻繁使用偉哥對吧)。
我們要優(yōu)化性能带迟,首先要搞明白是哪些因素會影響性能音羞?是體力不行就得加強鍛煉,是操勞過度就應該學會休息仓犬。
在我們的游戲中嗅绰,哪些因素會影響性能呢?
二搀继、 影響性能的因素有哪些窘面?
如果大家不知道如何分析,那我給大家引導下叽躯。
當你玩游戲的時候财边,首先是不是要將你的游戲加載到內存。前戲太長险毁,你肯定會等得不耐煩吧制圈,不爽,是不是要優(yōu)化畔况。那么第一個問題來了鲸鹦,如何優(yōu)化游戲加載速度(三、1)跷跪,我們先記錄下來馋嗜,下面逐一講解。
其次吵瞻,你好不容易把東西放內存里去了葛菇,但是屏幕沒任何東西,也不給你發(fā)出點聲音橡羞。這體驗不好眯停!也就是說屏幕渲染游戲界面耗時太長,卡頓卿泽,需要優(yōu)化莺债,所以,第二個問題签夭,如何優(yōu)化渲染速度(三齐邦、2)?
最后游戲運行過程中第租,運行速度受什么影響措拇?與設備內存、CPU慎宾、代碼有關丐吓,所以我們要做內存優(yōu)化(三浅悉、3)、CPU占用及性能優(yōu)化(三汰蜘、4)仇冯。
三、 性能優(yōu)化從哪些方面著手族操?
1. 如何優(yōu)化游戲加載速度【加載優(yōu)化】
問大家一個問題苛坚,你一個8M的東西和人家一個1M的東西,你說誰會先加載進去色难?肯定是1M的泼舱,所以首先要想方設法優(yōu)化包體大小。
【優(yōu)化包體大小】的方法有哪些枷莉?
首先想下你的包體里面有啥娇昙?哪些東西占用的內存最大,哪些東西壓縮的可能性最大笤妙?
項目路徑下有res冒掌、scenes、scripts蹲盘,還有游戲引擎股毫,等。
簡言之召衔,包體的組成分為:資源和代碼铃诬。
(1)資源:圖片、聲音苍凛、動畫等趣席。
避免大尺寸的圖片出現(xiàn):純色圖片或有規(guī)律的圖片用一像素的圖片表示,帶圓角的按鈕背景圖片用九宮格形式展示醇蝴。
另外有一點也要格外注意宣肚,cocos creator所支持的最大圖片尺寸為2048*2048,超過這個尺寸的圖片在顯示時會有問題悠栓,常見于一些Spine動畫打包出來后沒注意資源圖片尺寸钉寝,導致動畫顯示異常。
如果是地圖資源超過20482048闸迷,常見于一些mmo項目,這種情況下俘枫,需要對地圖資源進行切分腥沽,切分成小于20482048的若干圖片,在游戲中再拼接在一起鸠蚪。
圖片壓縮:
圖片的壓縮格式:背景今阳,jpg體積要小于png师溅,背景圖片jpg,很多圖片格式盾舌,導出美術圖后墓臭,這些圖,仍然可以壓縮妖谴。
百度搜索在線壓縮圖片窿锉,即可找到相應網(wǎng)站直接操作。
圖片分辨率: 1920x1080 > 960x540膝舅,減少分辨率嗡载; -->降低了清晰度的;
盡可能的時候九宮格的圖片仍稀,來代替一張整圖按鈕200x100洼滚, 300x100; -->大大的降低的圖片的分斌率技潘,這樣就可以節(jié)省資源遥巴;
類似這樣,將各個界面的美術資源享幽、幀動畫分類并且打包成圖集也是比較好的處理方法铲掐,將資源進行模塊化。這樣在加載時琉闪,以及游戲運行時迹炼,會有以下幾點好處:
1.提升加載速度
省去了多次打開/關閉文件所帶來的時間損耗
2.減少文件的體積
多張圖片合并到一起,在包體上面會有一定的優(yōu)化
3.減少DrawCall
使用時颠毙,由于這些美術資源都是一起配合使用的斯入,因此放在一張圖集中,可以減少渲染的DrawCall數(shù)量蛀蜜,對渲染的性能也有優(yōu)化的作用刻两。
同時在不需要使用這些資源時,比如說某個界面 不需要再顯示時滴某,可以將這個界面的資源統(tǒng)一釋放磅摹,避免占用內存。
另外通用資源可以統(tǒng)一打包在一張圖集中霎奢,讓這些通用的常用資源常駐與內存户誓,方便使用。避免頻繁的重復釋放和加載幕侠。
同樣帝美,聲音也可以采用相應方法處理。
音樂音效資源(壓縮格式背景音樂的大小晤硕,音樂的數(shù)量悼潭,聲道庇忌,采樣率)。
如下是壓縮后的音樂文件和壓縮前的音樂文件大小對比舰褪,縮小為壓縮前的十分之一了皆疹。
字庫:
盡可能的不要自己帶字庫。
(1)特效文字占拍,盡量使用位圖字體略就,幾個字母+圖片,體積遠遠小于一個完整的字庫刷喜,性能還要好残制,數(shù)字、界面的文字掖疮,例如我們的《極速賽車》中就是采用這種方案初茶!
bmpfont -- .png + .fnt文件;
(2)盡可能的使用系統(tǒng)字庫浊闪;
(3)字庫可以壓縮fontmin恼布;特定的數(shù)量固定的文字;
(4)位圖字與矢量字搁宾,哪個性能更好? ? ?
位圖字:速度快折汞,但是,內存大盖腿;
矢量字:速度慢爽待,但是內存小翩腐;
【預制體】:
首先先說一下prefab在使用時的步驟:從文件中讀取數(shù)據(jù) → 反序列化數(shù)據(jù) → 還原得到Prefab節(jié)點樹 → 預處理 → 實例化
Prefab這塊的加載優(yōu)化主要集中在兩個地方:一個是load加載耗時優(yōu)化鸟款,另一個是實例化耗時優(yōu)化。
①合理拆分Prefab
越大的prefab文件在加載過程中的耗時是越長的茂卦,而且通常不是等比何什,而是以類似平方曲線這樣的去增加時長的。
例如讀取一個100kb的文件等龙,可能耗時也就10毫秒处渣,但對于一個1M或者是2M的文件,我們在加載時就不是100毫秒蛛砰,可能就是幾百毫秒罐栈。
類似這樣七八百kb的prefab文件,我們就要去思考一下泥畅,是不是里面的節(jié)點都必須做成一個prefab悠瞬?
是否可以拆分成2個以上的prefab,通過拼接的方式組合?
一個prefab我們可以將它看作為一個功能模塊浅妆,而功能模塊并不是越大越好,而是功能職責越單一越好障癌,遵循這個原則凌外,我們可以對prefab做更好的拆分。
記滋握恪:職責單一原則康辑,邏輯清晰,解耦轿亮,便于后期維護疮薇。加載快!我注!
②延遲加載資源
在場景處可以找到按咒。
在Creator的資源管理器中點擊編輯好的prefab資源,在屬性檢查器中我們可以看到延遲加載資源的選項但骨。勾選這個選項可以減少prefab的加載耗時励七,但首次顯示的耗時會增加。
這是由于勾選后奔缠,Prefab所引用的資源掠抬,像圖片、音效這些校哎,不會在load時加載两波,而是會在Prefab第一次顯示的時候再進行資源的加載。因此需要根據(jù)具體的使用環(huán)境進行選擇闷哆。
③選擇優(yōu)化策略
在prefab的屬性檢查器中腰奋,我們可以看到優(yōu)化策略這個選項。這個也需要我們根據(jù)實際的使用情況進行選擇阳准。
當我們選擇“優(yōu)化多次創(chuàng)建性能”這個選項時氛堕,Prefab加載后會進行一個預處理的操作,這個預處理其實就是動態(tài)生成一些prefab的實例化代碼野蝇,并把這些代碼交給jit去進行優(yōu)化讼稚。
這樣在實例化時的耗時將會大大減少,相應的绕沈,在load時的耗時會有所增加锐想。
當我們選擇“優(yōu)化單次創(chuàng)建性能”這個選項時戏罢,prefab加載后會跳過預處理的步驟该编,這樣在加載時的耗時會減少很多,但實例化時的耗時會增加区拳。例如一些固定UI界面,由于方便加載場景或者時進行功能劃分藕帜,通常會做成prefab烫罩,這種prefab只會加載一次的,就可以選擇這個選項洽故,提升加載的性能贝攒。
需要注意的有一點:由于微信小游戲平臺禁用了動態(tài)加載代碼,類似eval這些不能使用时甚,因此優(yōu)化策略這個選項在微信小游戲平臺是無效的隘弊。
(1)代碼:
代碼體積(引擎+業(yè)務邏輯代碼) -大頭在引擎。
解決方案:引擎:非常簡單荒适,你只要把不要的模塊去掉就可以了梨熙,你要知道哪些模塊是占體積多的,物理引擎刀诬,能不用的模塊咽扇,就不用【肆校【項目設置】-【模塊設置】肌割,只打包必要模塊即可。能不用tilemap就不用帐要,因為Cocos中有足夠優(yōu)秀的2D編輯器把敞,可以替代tilemap,能用碰撞檢測引擎就不用物理引擎榨惠》茉纾可以通過項目設置,去掉游戲中沒有使用的功能模塊赠橙,減少包體大小耽装。如下圖,將不需要的模塊去掉期揪,再打包掉奄。
業(yè)務邏輯代碼一般我們也沒法修改,你的業(yè)務邏輯差不多凤薛,但是姓建,要注意一個95%以上的同學,都會忽略的一個事實:src文件夾內的settings文件缤苫。
其實settings文件大小是可以修改的速兔。首先大家要搞明白它的大小是由誰決定的? 如果你不搞清楚這個問題活玲,你就沒辦法優(yōu)化涣狗,即使別人告訴你這么做谍婉,你也會納悶。所有需要代碼加載的資源放到resources镀钓,否則堅決不放到resources文件夾內穗熬。因為程序不知道哪些資源需要加載,也不知道你什么時候加載掸宛,所以會一股腦在settings文件中建立資源的映射死陆。如下圖所示,將資源放在res中和將資源放在resources文件夾下唧瘾,settings文件的大小對比。
注意:需要清空build再打包别凤。
2. 如何優(yōu)化渲染速度【渲染優(yōu)化】
渲染方面優(yōu)化主要集中在如何降低draw call上饰序,draw call越多,渲染的壓力也就越大规哪,對應的幀率可能就會下降求豫,正常情況下如果draw call超過100就有可能帶來卡頓,所以要注意這方面的優(yōu)化诉稍。
draw call:游戲場景里面物體蝠嘉,分幾次提交給顯卡繪制,這個次數(shù)就是等于drawall次數(shù)杯巨。
100個物體蚤告,100次提交給GPU,就是100個draw call服爷。
draw call過高為什么會影響性能杜恰?
GPU:每次繪制我們的圖像---》一次能吞吐一定數(shù)目的三角形的,如果你的draw call過高,每次繪制的時候仍源,GPU本來可以一次吃更多的三角形心褐,但是你沒有讓我吃飽,GPU性能沒有發(fā)揮出來笼踩。
CPU:10個精靈逗爹,--》10張圖片;每次渲染管道里面再繪制的時候嚎于,只能帶一張紋理掘而, 每個精靈的紋理對象,是不一樣的匾旭, 所以無法合批()
到底什么樣的能在一個draw call里面繪制呢?
mesh相同---紋理相同镣屹,shader要相同,參數(shù)要相同,draw call合批-- >繪制;
比如价涝,10個物體:sprite1, sprite2, sprite3, label, 9宮格sprite, sprite;
推薦方法:
【1】合并渲染批次女蜈,降低 DrawCall,提升渲染性能
(1)使用自動圖集或使用 TexturePacker 對碎圖進行打包處理:只有圖集內的精靈才有可能在一個draw call繪制→合批.這樣操作的話,可以讓多個 Sprite 渲染的紋理都是同一張圖集圖片伪窖,合并這些 sprite 的渲染批次逸寓,就可以減少 DrawCall 以及 CPU 的運算開銷。
(2)合批的時候覆山,盡可能的不要打亂了合批:例如上面label的出現(xiàn)打亂了sprite的結構竹伸,就不能合批。
(3)為什么label會單獨做一個draw call簇宽? 文字會繪制在紋理中勋篓。
(4)資源處理,減少 Mask 組件數(shù)量:由于 Mask 組件需要在 stencil 和 content 前后都添加修改 gl 狀態(tài)的 render command魏割,因此使用 Mask 會打斷我們的 DrawCall 批處理譬嚣。
對于一些特殊的顯示,例如圓角的 icon 等钞它,如果條件允許拜银,盡量不要使用 Mask 組件來進行處理,而是通過對資源進行處理達到同樣的效果遭垛。
目前 Mask 組件尼桶、Spine 組件、DragonBone 組件都會打斷批處理锯仪,在節(jié)點結構上我們要避免被打斷的情況發(fā)生泵督。
(5)復用節(jié)點,減少節(jié)點數(shù):當顯示或隱藏這個界面時卵酪,大量的節(jié)點會帶來大量的 enable 和 disable 的開銷幌蚊。比如好友排行,假設有1000名好友溃卡,沒必要設置1000個節(jié)點溢豆,設置一頁顯示的節(jié)點即可,之后更換這些節(jié)點的顯示內容瘸羡。
最快的辦法就是合并碎圖成圖集漩仙,然后同一圖集的按照順序擺放節(jié)點,中間不能插入其他圖集的節(jié)點犹赖。
3. 內存優(yōu)化
靜態(tài)資源的內存管理:
靜態(tài)資源指的是場景中直接或間接引用到的所有資源(腳本動態(tài)加載的資源不算在內)队他。
在場景資源的屬性編輯器中可以勾選“自動釋放資源”選項,從而在切換場景時峻村,會自動將舊場景使用的靜態(tài)資源釋放掉麸折,從而節(jié)省內存的占用。
動態(tài)資源的內存管理:
動態(tài)資源統(tǒng)一使用cc.loader進行資源的加載以及管理粘昨。參考:動態(tài)加載
要注意的一點是垢啼,CocosCreator中通過cc.loader去加載資源的所有方法窜锯,都是異步的。所以需要在回調中芭析,確認加載完成后才能使用資源锚扎。也可以通過cc.loader.getRes這個API去同步的獲取資源,但需要對get到的資源進行檢查馁启,如果沒有加載或者沒有加載完成驾孔,則需要等待或者通過cc.loader進行加載。
這樣的話整個代碼會清晰一些惯疙,避免掉入JS的回調地獄中
例如:
_loadRes = function(url, type, callback){
cc.loader.loadRes(url, type, function(){
if(!err){
callback(prefab);
}
});
}
Cc.loader.getRes
_createPrefab(url){
var prefab = cc.loader.getRes(url, cc.Prefab);
If(prefab !== null && typeof(prefab) !== "undefined"){
return cc.instantiate(prefab);
}
return null;
}
通過簡單的封裝兩個方法翠勉,在使用時可以保持代碼的整潔易讀。
另外一點需要注意的是霉颠,當批量進行加載時眉菱,cc.loader也提供了onProgress回調,這個回調中的三個參數(shù)中掉分。
totalCount并不是指的是加載的資源總個數(shù),而是加載這個資源所需要加載的依賴項個數(shù)克伊。比如加載一個SpriteFrame酥郭,它的totalCount就是3,這3個item分別為:json愿吹,texture2D和SpriteFrame不从。
所以當totalCount為0時,并不是代表加載資源總個數(shù)為0犁跪,而是意味著這些資源已經加載過在內存中了椿息,可以直接使用。
復用一切可復用的對象
最后是內存使用的一個理念:復用一切可復用的對象坷衍。
復用寝优,并不僅僅是為了節(jié)省對象在alloc造成的開銷,更重要的是避免GC時帶來的額外開銷枫耳。
像一些戰(zhàn)斗中的掉血數(shù)字乏矾,敵人的血槽,怪物迁杨,子彈钻心,英雄頭像等等,都是我們常城π回去做復用的地方捷沸。
對于常見一些復雜對象,我們可以使用對象池NodePool進行復用
對于基礎的對象我們可以直接進行賦值從而達到復用的目的狐史。
1. CPU及性能優(yōu)化
1痒给、絕對避免游戲中出現(xiàn)死循環(huán)说墨。
2、控制游戲幀率侈玄。
3婉刀、H5游戲,JS代碼級別優(yōu)化
for(var i=0,len=arr.length; i<len; i++){
}
4.JS異常捕獲
Try_catch
一單拋出異常序仙,效率就會直線下降突颊。盡量避免在for循環(huán)中try。潘悼。
5.全局變量的使用要慎重B赏骸!
6治唤、優(yōu)化節(jié)點樹棒动,減少節(jié)點數(shù)量。
7宾添、場景中不要掛載過多的Prefab船惨,可適當將一些Prefab變成動態(tài)加載的。
四缕陕、 性能優(yōu)化應注意什么粱锐?
效率、成本扛邑。不要花百分之九十的時間怜浅、成本去嘗試獲取百分之一的性能提升。
很多時候蔬崩,需要兩害相權取其輕恶座。