CocosCreator客戶端優化系列(四):CPU占用及性能優化


原文鏈接:https://blog.csdn.net/zzx023/article/details/88991314

 

這篇文章是優化系列的最后一篇了,內容會長一些,更多的是提供一些方向以及思路,具體的一些細節由於篇幅有限,就不一一說明了,只要找對方向,就可以慢慢研究。希望大家可以耐着性子看完。

使用Performance定位問題

 

 

針對CPU占用的情況,我們有很多的優化方案,但實際的項目開發過程中,更重要的是找到哪個地方是問題點。只要我們能夠快速的找到問題點,那么解決方案也就應運而生了。
通過google開發者工具中的Preformance工具,可以截取一段時間內,程序運行的情況進行分析。如果在某一段時間內,CPU占用過高,導致幀率下降卡頓,那么我們可以在結果中像上圖一樣看到存在紅色的熱點幀。
通過針對這些熱點幀的調用棧的分析,我們可以找到是哪一些接口的CPU占用情況比較嚴重。在找到熱點函數后,我們就可以針對具體的函數做優化。

總之需要注意的是:
1、觀察整體性能
2、觀察分析局部熱點幀
3、通過調用棧分析熱點

具體的使用方法可以參考google的文檔

使用ESLint
很多時候我們的CPU占用過高,經常是由於我們在編碼過程中對於語法的不注意,或者是疏忽導致的。包括一些內存泄漏的問題,閉包的處理等等。
這里推薦一款插件,可以幫助我們強制寫出高質量且整潔的代碼,使得一些語法規范上面導致的問題可以被我們提前預防。

 

 

 

ESLint這是一款js語法規則和代碼風格的檢查工具,類似的工具還有TSLint,JSHint這些。
使用的話只需要通過npm進行安裝

npm install -g eslint

 


在安裝完成后,通過

eslint --init

 


生成配置文件,在配置文件中可以根據項目的語法規范進行相應的配置。
具體可以參考:https://cn.eslint.org/docs/user-guide/configuring

-控制游戲幀率


分離邏輯幀以及渲染幀

 

 

 

參考上面mainloop的代碼,在默認的情況下面,我們的邏輯幀和渲染幀是相同的幀率,默認都是60幀。
但實際的項目開發過程中,像一些回合制的游戲,卡牌類游戲,或者是一些不需要太實時的游戲,實際上並不需要邏輯保持60幀的幀率在運行,從而造成性能的浪費,導致手機的電量消耗以及發熱嚴重。

這時我們就可以將這一段代碼進行改造,定制一下引擎,利用fixUpdate的方式,我們可以很輕松的將邏輯幀以及渲染幀進行分離。比如渲染幀保持60幀,而邏輯幀按照30幀的幀率運行。

這樣邏輯幀和渲染幀就分離開來了,在運行時,邏輯幀的幀率我們可以統一設置,也可動態控制。
比如在需要創建大量對象時,我們就可以動態的提高邏輯幀的幀率,配合之前說過的async,從而加速對象的創建。
又比如在一些需要網絡同步的游戲中,我們可以通過渲染幀幀率比邏輯幀高的特性,將一些因為網絡問題導致的堆積數據取出來,采用一些插值算法,讓渲染幀進行平滑的過渡渲染。這樣就不會發生突然的瞬移同步。

-控制物理系統以及碰撞系統的幀率


如果有使用到物理系統,也可以去控制物理系統的幀率。參考官方文檔:https://docs.cocos.com/creator/manual/zh/physics/physics/physics-manager.html#%E8%AE%BE%E7%BD%AE%E7%89%A9%E7%90%86%E6%AD%A5%E9%95%BF

默認物理系統的幀率與游戲幀率是一致的,但有些時候我們如果只是做粗略模擬的話可能並不需要這么高的幀率。這時我們可以通過一下的一些參數設置來控制物理系統的幀率:

 

 


對於碰撞系統來說,我們就需要使用fixUpdate的方法去定制一下引擎,修改CCCollisionManager.js中的這段代碼。

 

 


需要注意的是,當我們降低了物理系統的幀率或者碰撞系統的幀率時,有可能會發生漏判的情況。這時由於物體的運動速度較大導致的,所以在調整幀率時,我們需要確認在游戲的設計中,物體的最大速度是多少?需要判斷的物體最小體積是多大?再根據這些信息去調出合適的幀率,這是個需要反復調整的過程。

- JS代碼級優化


很多時候我們對於CPU的優化都會從算法的方面着手,關於算法這一塊優化方案多種多樣,很多都需要根據項目的實際情況以及游戲的設計出發的。
我們經常會聚焦於算法級的優化上,而忽略掉代碼級的優化。
這里帶來的就是代碼級的優化

1、數組操作
增加數組元素時,更推薦使用:

 

array[array.length] = 0;

 


相比較push的方法,代碼執行效率上我們可以看下對比:

 

 

 

會有一定的提升,但提升的空間有限,因此不是強烈推薦,只是針對需要反復大量執行的代碼時,更推薦使用。比如大量的a星尋路計算時,可以在編碼時隨手注意一下

2、for循環
常用的for循環我們有幾種方式

for(let i = 0;i < arr.length; i++)
for (const key in arr)
for (const key of arr)
arr.forEach(element => {})

 


除了for-in這種方式外,其他三種for循環方式沒有什么太大的差距

 

 

 

強烈不推薦使用for-in的方式進行for循環,效率極其低下,同時隨着游戲不斷的運行,for-in還不能被jit優化。因此千萬不要使用for-in

3、arguments
js中如果要實現類似C++中的多態,可以通過arguments去達到。
這樣我們可以通過相同的接口,只是參數的不一致從而達到不同的邏輯運行效果

 

function argumentsTest () {
  if (arguments.length === 1) {
  //......
  }
  else if (arguments.length === 2) {
  //......
  }
}

 


類似上面這樣的使用。
這種方式雖然使用上看起來很秀,但要注意的是,性能也是極其低下的,需要這種情況,不要偷懶,多寫幾行代碼,拆分成幾個不同的函數進行調用會更好。
強烈推薦不要在工程中使用arguments

4、try-catch or try-finally 以及 eval
強烈建議不要使用任何的try-catch or try-finally 以及 eval,執行效率極其低下,很容易造成游戲的卡頓。
例如try-catch or try-finally系列,如果沒有錯誤拋出,那就還好。一旦有錯誤拋出,效率直線下降。

5、global value
在使用全局變量時,類似下面這樣

gIndex = 0;
for (let i = 0; i < n; i++) {
  gIndex += i;
}

 

 

 


執行結果:
不要直接使用gIndex,使用局部變量進行一下轉換,效率會快很多:

 

var localIndex = gIndex; 
localIndex = 0;
for (let i = 0; i < n; i++) {
  localIndex += i;
}

 

 

 


執行結果:

以上就是一些代碼級優化上需要注意的地方,可以看到,如果時一些熱點函數,需要大量重復執行的話,如果使用這些優化方案,通常會帶來很大的提升。這也是從另一個角度去進行CPU性能的優化


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM