6連招!Cocos卡牌游戲優(yōu)化技巧(建議收藏)
OMNIDREAM GAMES 是一家核心團隊在卡牌品類有著超過8年積累的開發(fā)商,旗下以《新斗羅大陸》為代表的系列產品累積流水破40億,用戶總數4000萬+。
在多年開發(fā)過程中,OMNIDREAM GAMES 團隊積累了一套游戲優(yōu)化方案。今天我將基于團隊一款全新的卡牌游戲「omniheros」,和大家分享幾個行之有效的卡牌游戲優(yōu)化方法,以及自己的一些心得。本文為將重點介紹以下6個優(yōu)化方法:
紅點設計:減少判斷邏輯重復計算,支持多個顯示類型和周期刷新。
音頻加速:支持不同音頻自定義變速。
ASTC 分塊壓縮:減少內存、提升加載速度、更精確地選擇壓縮塊大小。
性能分級:讓高、低端機性能均有提升。
動態(tài)繪制:減少 overdraw、降低 drawcall、提高幀率。
小包策略:減少首包包體、提升流暢度。
1、紅點設計
解決問題
減少判斷邏輯重復計算。
紅點之間父子關系清晰可見。
支持多種顯示類型。
支持周期刷新。
紅點樹的構想
每個 UI 需要顯示的紅點都對應有一個 id。
用樹結構建立紅點與紅點之間的層級關系。
使用數據結構,保存紅點的激活狀態(tài)。
紅點樹的設計
只有葉子節(jié)點才有且必須有自己判斷邏輯。
葉子節(jié)點的判斷方法不需要參數或者需要固定的參數。
非葉子節(jié)點的紅點顯示狀態(tài)取決于他的子節(jié)點的顯示狀態(tài)。
業(yè)務層只需要關心每個子節(jié)點的判斷邏輯,何時刷新,刷新時是否需要傳參數即可。
紅點激活流程
-
104,105,106,107,108為葉子節(jié)點,分別綁定了自己的 check 方法。
-
104的 check 方法里有一個固定傳參1,這個參數在每次判斷的時候都會傳入。
-
當105在 func(2) 的判斷下從未激活變成了激活,會將狀態(tài)傳給101,101有一個激活狀態(tài)的子節(jié)點,不需要管其他子節(jié)點,自己也會變成激活, 并將激活狀態(tài)傳給100,而使得100也變成了激活。
-
當107在 func() 的判斷下變成了未激活,會將狀態(tài)傳給103,103只是根據107的未激活并不能直接決定自己的激活狀態(tài),它需要檢查其他子節(jié)點的狀態(tài),所以需要檢查108的激活狀態(tài),若108是激活的,則自己激活;若108未激活,則自己未激活,并將狀態(tài)傳給100。
-
如果107檢查前和檢查后的狀態(tài)有變化則會將狀態(tài)傳給父節(jié)點103,如果沒有變化則不用向父節(jié)點傳遞。
參數混合樹狀結構
葉子節(jié)點所需要的參數不固定,即需要動態(tài)參數。
非葉節(jié)點的子節(jié)點需要相同的動態(tài)參數。
非葉節(jié)點的子節(jié)點需要不同的動態(tài)參數。
紅點激活流程
-
104,105需要相同的動態(tài)參數 e1,即101的子節(jié)點需要相同的動態(tài)參數。
-
107需要動態(tài)參數 g1,108需要動態(tài)參數 g2,即103的子節(jié)點需要不同的動態(tài)參數。
-
在動態(tài)參數的樹結構里,對于葉節(jié)點107或者105,沒法確定其他兄弟葉節(jié)點的參數是否與自己一致,所以這里需要遵循一個原則,只有激活狀態(tài)可以傳給父節(jié)點,動態(tài)參數不能傳。
-
對于103,子節(jié)點需要不同動態(tài)參數,所以對于107和108的刷新只能選擇各自分別刷新,然后同時將狀態(tài)傳給103。
-
對于101,子節(jié)點需要相同動態(tài)參數,所以對于104和105的刷新可以選擇各自分別刷新,也可以選擇刷新101并且將動態(tài)參數傳給子節(jié)點104和105。
列表結構紅點
因為列表每個元素不固定,元素數量不固定,所以沒法綁定紅點 id,即列表的紅點處理目前選擇自己判斷,不走樹結構。
紅點配置表
id 為紅點對應 id,有些 id 可能為虛擬 id,在 UI 里沒有對應界面。
name 為注釋。
parent 紅點的父節(jié)點,只有大的根節(jié)點沒有父節(jié)點。
update_type 更新類型:
默認為0前端判斷,通過綁定的檢查方法判斷;
可以設置為1后端判斷,因為在登錄游戲到主城過程里,部分功能是不需要拉取對應的消息的,那這部分的紅點激活狀態(tài)沒法通過數據的邏輯判斷,只能靠服務器判斷之后將結果返回,等到進入對應功能拉取到該功能信息以后,才接管為綁定的檢查方法判斷。
refresh_type 刷新類型:
默認0及時刷新,無需標記;
1為登錄刷新,每次登錄只紅一次,標記過后這次登錄就不會再紅了;
2為每天刷新,每天只紅一次,標記過后這天就不會再紅了;
3為每周刷新,每周只紅一次,標記過后這周就不會再紅了。
function_id 為功能 id,用于紅點功能開啟判斷,減少無效的判斷耗時。
priority 優(yōu)先級,在 update_type 為1時,可以設置優(yōu)先級讓比較簡單的判斷邏輯先判斷,減少后端判斷耗時。
show_type 為顯示類型,配合顯示優(yōu)先級使用,優(yōu)先級越高先顯示,可自由設置每個顯示類型對應的顯示優(yōu)先級:
默認0,紅色的點;
1為綠色箭頭,只顯示綠色箭頭;
2為滿,只顯示滿;
3為新,只顯示新;
-1為任意類型,取決于判斷邏輯或子節(jié)點傳給的顯示優(yōu)先級最高的類型。
紅點業(yè)務開發(fā)工作
配置紅點 id 關系表。
在 UI 上掛載紅點顯示組件。
綁定紅點 id 的檢查方法。
在需要變化的時候刷新紅點。
標記紅點是否點擊過。
2、音頻變速
解決問題
音頻可以設置變速。
不同音效可自定義不同的變速。
音頻變速幾種方式
修改底層支持音頻變速。
接入 wwise 引擎。
接入 fmod 引擎。
修改底層支持音頻變速
修改 AudioMixerController.cpp,支持音頻縮放。
優(yōu)點:
開發(fā)速度快,只需要修改底層代碼。
實現成本低,沒有額外花銷。
缺點:
只有一個通道,所有音頻只能同時變速。
接入 wwise 引擎
wwise 是一款針對游戲開發(fā)的綜合音頻中間件解決方案,可創(chuàng)建精密、豐富的互動音頻。它由緊密集成的設計工具和聲音引擎構成,可讓聲音設計師和程序員在更短的時間內更經濟地完成令人震憾的音頻。
wwise 官網:
優(yōu)點:
音頻效果相對較好。
音頻共享,音頻資源大幅縮減。
對程序比較友好,發(fā)事件即可。
缺點:
需要學習 wwise 軟件。
價格相對較貴,成本高。
web 端沒法支持,沒法直接播放 MP3,開發(fā)不方便。
預編譯庫特別大。
接入 fmod 引擎
fmod 引擎是一種跨平臺的音頻引擎,可以在 windows,安卓,iOS,web 等開發(fā)平臺使用??稍O置多個通道,對單個通道進行變速,例如游戲只希望對技能音效進行變速。
fmod 官網:
優(yōu)點:
支持不同通道變速。
可以直接播放 MP3。
較為便宜。
缺點:
文檔全英文。
3、ASTC 分塊壓縮方案
解決問題
減少圖片的內存。
提升圖片加載速度。
更為精確選擇壓縮塊大小。
什么是 ASTC?
同 pvrtc、etc1 etc2,一種圖片壓縮紋理格式。
優(yōu)點:
壓縮倍率更高,壓縮率可自由選擇。
顯示效果更好。
兼容 iOS 和安卓。
支持情況:
需要 OpenGL ES3.0 以上才支持,根據調查,我們發(fā)現海外有99.2%的玩家手機是支持,不支持率僅占0.8%,而且這種情況在國內是更為樂觀的。針對這部分玩家,我們可以選擇拋棄,也可以選擇做軟解支持一下,只是這軟解會比較慢。
Cocos Creator 接入 ASTC:
Creator 3.0 以后支持 ASTC。
Creator 2.4 需要修改 C++ 底層邏輯來加載 ASTC,這部分網上是有現成例子的。
ASTC 壓縮分塊
我們了解過 ASTC 后,發(fā)現這種紋理其實是有很多分塊壓縮方式。如圖,分塊越大,壓縮倍率越高,當然圖片的質量會越低,那么我們應該如何選擇分塊呢?
對此很多團隊其實提出一個比較好的方式就是對文件夾配置白名單,如下圖:
這樣確實能找到比較好的壓縮分塊,但是如果下面兩張圖片在同一個文件夾:
左邊的圖片細節(jié)比較多,顏色比較豐富,選擇 6x6 的方塊才能有比較好的顯示效果,而右邊的圖片色彩較為單一,只需要選擇 10x10 甚至 10x12 都可以,如果我們按照文件夾的方式,對右圖進行 6x6,其實會是壓縮倍率不夠造成浪費的,所以對文件夾進行白名單方式是比較難對單個圖片找到最合適的分塊方案!對此我們提出了一個較為準確的一個方案——相似度匹配的方案。
相似度匹配的方案
對每一張圖片把所有的分塊都提前轉好。
按塊的尺寸從大到小和原圖進行相似度匹配。
擬定一個相似度值,例如:80%為通過。
-
部分圖片也支持白名單方式:
這樣主要是比較原圖與壓縮圖的相似度,找到我們認為比較合適的壓縮比。那么如何去實現這相似度匹配呢,這里我們提供了一個相似度匹配算法僅供參考。
相似度算法
按照所選的塊大小把圖片分成很多塊。
每一塊的每個像素 rgb 值的差值,乘以該像素的透明度,求出差值 rgb 的亮度。
把單個塊所有像素的差值亮度求一個均值。
比較所有塊的亮度差值,得到一個最大的亮度差值。
轉換成一個0到100的百分比,作為可配置參數。
如圖,A 的分塊顏色信息較多,B 的顏色較為單一,壓縮后A的差異性是所有方塊最大的,我們就會選擇 A 作為整個圖片的差異性,目的是為了顯示效果更加準確,優(yōu)先保美術品質。
相似度算法優(yōu)缺點
優(yōu)點:
對圖片選塊較為準確,對每張圖片都單獨選塊。
游戲性能與表現效果,優(yōu)點考慮了表現效果。
缺點:
需要在電腦里緩存所有的塊圖片。
比較慢(git 鉤子)。
4、性能分級方案
解決問題
高端機有更好的效果。
低端機也能有比較好的體驗。
分級流程
統(tǒng)計2021海外 top150,做出分級(iOS 直接白名單)。
獲取手機設備信息(手機型號、CPU 最大頻率、GPU 頻率、最大內存、剩余外存、核心數)。
設定各個參數對應的分數系數,計算總分:
score = cpuScore*Pcpu*Rcpu + gpuScore*Pgpu + ramScore*Pram + memScore*Pmem
根據總分做出高中低分級,進行不同的操作:
LOW:score < Smiddle
MIDDLE:Smiddle <= score < Shigh
HIGH:score >= Shigh
分級處理
預加載數量設置
設置界面是否常駐
對象緩存數量
調節(jié)游戲幀率
資源回收頻率
特效播放分級
……
性能測試標準分級
性能分級后,不同機型的性能標準不一樣
這種分級解決了大部分表現效果對手機硬件的匹配,但這個過程中我們觀察到部分手機可能 CPU 計算能力不怎么好,但是內存比較高,所以我們做了更為細化的分級方案。
細化分級
主要為了充分利用手機硬件的各項優(yōu)勢:
CPU 分級:幀率、回收頻率、特效播放分級……
內存分級:預加載、界面常駐、對象緩存數量……
5、動態(tài)繪制
解決問題
減少 overdraw。
降低 drawcall。
提高幀率。
Cocos 渲染痛點
畫 UI 的方式,沒有非透明的剔除機制,針對這一點,一般的優(yōu)化手段就是減少繪畫次數,畫一次就保存起來,對此很多游戲都用一種比較實用的優(yōu)化方式。
動態(tài)繪制彈框
在彈框顯示時,設置截圖模糊墊在彈框后面。
然后將模糊圖后面的場景都隱藏掉。利用這個思路,在此基礎上可以做一些其他優(yōu)化。
動態(tài)相機優(yōu)化
如下圖,對 camera 新建一個分組 postRender。
把需要優(yōu)化的節(jié)點,如比較復雜的列表,分配到 postRender 這個分組,這樣主 camera 就不會渲染列表了。
postRender 對列表繪制一次,保存貼圖 postImage,把 postImage 渲染給主 camera。
在界面靜止的狀態(tài)下,關閉 postRender 繪制,有變動再打開。
這樣的目的是利用另一個相機對這個復雜的 UI 只渲染一次,讓主相機對這個復雜 UI 的渲染轉變成對一張貼圖的渲染,這樣的方式結果就是:
多了一張 postImage 內存。
列表部分就只有一個 drawcall。
效率提升了很多,如下圖,drawcall 減少了很多,fps 也提升比較大。
優(yōu)化前
優(yōu)化后
動態(tài)大地圖優(yōu)化
下圖是一個大地圖 UI,手機顯示的部分只有中間藍色框那么大,但是地圖卻超出了很多,且有多個分層和特效,而且會多復制一份作為循環(huán)移動的銜接,所以加載這么一個大地圖 UI 需要的時間不少,比較差的機型打開這個界面必然會出現黑屏時間,為了解決這個黑屏時間,我們也做了一個比較好的優(yōu)化。
優(yōu)化步驟
-
在游戲根節(jié)點上新建一個常駐緩存節(jié)點 preloadNode。
第一次打開地圖加載完成時,渲染截圖一張第一屏的場景。
將截圖綁定到一個新建的 node,緩存在 preload 節(jié)點上。
后續(xù)打開的時候,先將緩存的 node 先放在地圖節(jié)點顯示。
等大地圖加載完成,再把新的渲染場景重新截圖綁定到緩存節(jié)點,放回 preload 節(jié)點。
優(yōu)化結果
這樣利用這個緩存的截圖可以有效的避免了加載黑屏時間,除了大地圖,也可適用于其他加載黑屏的場景,如果覺得這個緩存截圖可能會造成較大的內存開銷,可以利用貼圖尺寸減半的方式減少內存開銷
6、小包方案
解決問題
減小首包包體(200M 以下)。
資源可以邊玩邊下載。
玩家玩的過程盡可能流暢。
樂變小包流程
跑一遍游戲前期,得到這個過程所用到的小包資源。
重新打成小包,剩余資源作為小包的補包打成 zip 分包,整包 = 小包 + 分包。
上傳一份包含所有散文件資源的文件包在服務器。
小包安裝啟動后,后臺會下載分包,每下載完成一個就解壓。
游戲過程中如果用到手機里沒有的資源,則立馬從有所有散文件資源的服務器下載。
存在問題
這個流程整體還是比較完善的,但是會有一個問題,下載分包需要時間,如果在玩游戲過程中,用到的分包里的資源,就需要從散文集列表的下載,等待下載完成才能繼續(xù)進行,造成游戲的卡頓,為了優(yōu)化這個問題,結合我們游戲是散文件更新方式的形式,我們在此小包基礎上做了優(yōu)化。
天神小包流程
打包時,我們記下這個包所有的資源為 List_all。
跑游戲前期,標記所有用到的資源,記錄資源列表 List_small,并且這個 List_small 是有序的。
按照小包大小要求打包,把 List_small 里按順序打進包里,直到達到小包限定大小,沒有打進包里的列表重新生成一個 List_pre 作為優(yōu)先下載隊列。
進入游戲后首先執(zhí)行正常的強制更新(對比的是 List_all 和當前線上版本資源的差異)。
游戲過程中優(yōu)先下載 List_pre 里的資源,如果有用到的資源而本地沒有也會立即去下載。
其他小包缺少的資源在后臺下載(List_small 和當前線上版本資源缺少的部分)。
后臺需要限制下載線程數量,保證玩家正常游戲。
提升點
小包大小可以按照要求自由控制。
List_pre 可以按照順序優(yōu)先下載,盡量保證用到的資源能提前下載好。
可控制的下載線程保證玩家體驗。
個人心得
其實,各種優(yōu)化方向都是在原有基礎上提出更高的要求,需要我們去大膽嘗試解決方法并充分驗證,最后再合理的范圍內做出取舍,從而實現更好的游戲優(yōu)化效果。
另外,在游戲開發(fā)中,性能方面其實有很多方面都可以有優(yōu)化空間。本次選取的是我們團隊積累的比較典型的幾個方案,如果小伙伴有興趣,可以在評論區(qū)一起交流。
-
Cocos Store 免費游戲資源下載指南! -
Creator 3.x 入門修煉指南(1) -
Creator 3.x 入門修煉指南(2) -
Cocos Creator 3D殘影特效,簡直太酷了!
-
史上最強CocosShader學習資源推薦(建議收藏)
