Cocos2D手機游戲開發之優化篇

Cocos2D手機游戲開發之優化篇

在這個手機游戲盛行已久的年代,一款產品想要博得更多用戶的喜愛就要在細節上做得更加到位。而游戲的優化在這里面起到了非常關鍵的作用。試想下,一款畫面和玩法都深受用戶喜歡的產品,卻只能在高端機子上面運行起來,或者就算運行起來也是各種卡頓、閃退,這樣的結果相信不是任何一個游戲人愿意看到的局面吧。

相比于PC游戲,手游在內存上基本可以說是錙銖必較,一款非常普通的android機子想要運行一款稍微龐大點的游戲,內存的限制是非常苛刻的。所以,管理好內存的使用有時候也是衡量一名游戲人的重要標桿。

一、內存優化

在游戲中,占用內存最多的無非就是圖片資源,所以如果可以從圖片資源上面進行優化,那么得到的收益將會是最大的。

1.1、資源占用

首先,先來看一下一張 144X144 的圖片在物理磁盤上面的占用的存儲空間大概是30KB,但是使用Cocos2D游戲引擎加載到內存里面,它需要占用至少256KB的大小。

主要的原因有以下兩個:

  • Cocos2D在像手機申請紋理圖片內存的時候,只能將圖片的寬高尺寸以2的n次冪大小來計算。
  • Cocos2D默認的紋理深度是32位。

對于第一點,由于144并非是2的次冪數,與之相近的2的次冪數分別是128和256。如果使用128,那么申請到的內存空間顯然無法存放 144X144 這么大的圖片,那么只好使用256來進行計算,也就是Cocos2D會把它當成 256X256 大小的圖片來申請空間,但是圖片本身沒有那么多數據,所以造成了內存空間的浪費。

關于第二點,Cocos2D使用32位的像素格式來保存像素信息,也就是圖片上的一個像素需要占用32位(bit)。一個字節(byte)又等于8位(bit),所以一個像素需要占用4個字節(32 / 8)的大小。

所以,可以輕易的得出 144X144 圖片占用的內存為:

【內存 = 圖片的寬 X 圖片的高 X 4byte】

也就是:

256 X 256 X 4 = 262144 byte

然后,1KB = 1024byte,所以它占用的內存大概是256KB(262144 / 1024)。

1.2、合理利用內存

根據上面1.1提到的兩點浪費內存的原因,我們就可以對癥下藥了。

對于圖片尺寸導致的內存浪費問題,我們可以將很多小張的圖片合成一張大張的紋理圖,讓大圖的尺寸等于2的n次冪,這樣我們就可以盡可能的去利用那些原先被浪費掉的內存。

合成大圖的工具有很多,我個人比較推薦使用TexturePaker,這個工具有mac和win版本的,而且操作和界面布局基本一致。關于TexturePaker的用法,網絡上面的教程很多,可以自行搜索。

這里要說的一點是Publish導出紋理集的時候要** 選擇格式為“Cocos2d plist(*.plist)”格式 **,這樣Cocos2D游戲引擎可以直接加載并解析。

導出紋理集格式

不同的設備由于設備硬件的不同,可以加載的圖片的最大尺寸也不同,所以我比較建議最大的紋理集尺寸為 2048X2048 ,這樣可以保證在所有的主流設備上面都能夠得到正確的加載。

1.3、修改像素格式

圖片上面每個像素都有RGBA四個通道,RGB三個通道用于表示該像素的顏色值,A通道用于表示Alpha(透明)通道,每個通道默認使用8bit的內存來存儲數據,所以總共是32bit。

32位的圖片可以表示16,777,216種顏色,對于手機游戲,很多時候并不需要使用這么多種顏色,很多顏色肉眼也很難分辨出來。所以,32位的位圖本身也挺浪費內存的,但是值得慶幸的是,Cocos2D允許開發者手動設置像素格式,代碼如下:

-- 設置像素格式為RGBA4444(16位)
CCTexture2D:setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_RGBA4444)

【我使用的是quick-cocos2d-x,所以代碼的語法都是lua的。】

Cocos2D游戲引擎支持的像素格式如下:

  • kCCTexture2DPixelFormat_RGBA8888
  • kCCTexture2DPixelFormat_RGBA4444
  • kCCTexture2DPixelFormat_RGB5A1
  • kCCTexture2DPixelFormat_RGB565

【說明】:

1、kCCTexture2DPixelFormat_RGBA8888:默認的32bit像素格式。

2、kCCTexture2DPixelFormat_RGBA4444:16bit像素格式,RGBA每個通道僅用4bit來存儲數據,由于每個通道的內存減少了一半,所以能表示的顏色也會相應的變少。如果可以,我一般都盡量使用這種格式。

3、kCCTexture2DPixelFormat_RGB5A1:16bit像素格式,該格式分別使用5個bit的空間存儲RGB顏色值,然后只用1bit表示透明值,所以它表示的顏色會比kCCTexture2DPixelFormat_RGBA4444更加的豐富,但是在透明度上只能表示全透明和不透明,無法表示半透明。

4、kCCTexture2DPixelFormat_RGB565:16bit像素格式,該格式將16bit都用于表示顏色,沒有透明通道,所以沒有辦法表示透明像素,通常游戲的背景圖可以設置成這樣的格式。

除了上述四種格式之外,其實還有其它的像素格式,比如:8bit等,但是它們可能無法滿足我們對游戲畫面的需求,所以比較有用的就上述這幾種。

【注意】由于設置像素格式是對全局進行操作的,所以一旦修改紋理的像素格式之后,后面加載的紋理格式就全部變掉了,如果想要恢復32bit深度,需要再次進行設置。當然,已經被加載到內存中的紋理不受影響。

二、渲染優化

游戲都是刷幀實現更新的,Cocos2D游戲引擎默認幀數是一秒鐘60幀,也就是一秒鐘要更新60次。但是設備的運算性能總是有限的,所以如果一幀之內的運算量過大,那么游戲更新一次的時間就會越久,一秒鐘就無法達到60幀的更新速率,也就是我們常說的掉幀現象。對于Cocos2D游戲而言,一般幀率低于40幀,玩家就能明顯的感覺游戲運行不流暢,畫面卡頓。

2.1、批量渲染

Cocos2D在進行畫面更新的時候,繪制一個精靈節點(CCSprite)需要通過如下三個操作:

打開 -> 繪制紋理 -> 關閉

那么如果一個場景里面有10000個精靈對象需要繪制,一幀的更新在渲染時候就要進行30000次(3*10000)完整的繪制操作。雖然手游很少會有一個場景里面10000個精靈的情況,但這無疑是一個要命的問題。

好在Cocos2D游戲引擎可以使用CCSpriteBatchNode來批量繪制精靈,創建CCSpriteBatchNode對象的代碼如下:

local  batchNode    = CCSpriteBatchNode:create("node.png", 300)

創建CCSpriteBatchNode的時候需要兩個參數,第一個參數是要批量繪制的精靈圖片路徑,第二參數是該CCSpriteBatchNode對象一次繪制的精靈個數【可以缺省】。

創建好CCSpriteBatchNode的實例對象后,就可以根據CCSpriteBatchNode的對象來創建精靈了,代碼如下:

local node  = CCSprite:createWithTexture(batchNode:getTexture())

從CCSpriteBatchNode的實例對象中取得紋理對象,然后根據該紋理對象創建精靈。將創建的精靈添加到CCSpriteBatchNode對象上,然后將CCSpriteBatchNode實例對象添加到層(CCLayer)上面。這樣,創建的精靈便會被顯示在游戲場景中。

由于CCSpriteBatchNode使用的是同一份紋理,所以用它來進行批量繪制的操作如下:

打開 -> 繪制紋理 -> 繪制紋理 -> ... -> 繪制紋理 -> 繪制紋理 -> 關閉

使用CCSpriteBatchNode渲染10000個精靈還是需要進行10000次的繪制紋理操作,但是只需要打開和關閉一次,也就是省去了9999次的打開操作和9999次的關閉操作。

如果游戲開啟FPS顯示的話,明顯的可以在左下角看到繪制次數從10000變成了1,而且幀率也會有所提升。

2.2、多紋理批量渲染

由于CCSpriteBatchNode創建的時候只能指定一張紋理圖,所以在使用上面有一定的限制。比如有多個不同的紋理要進行批量繪制的時候,我們只好創建不同的CCSpriteBatchNode對象。

但是還有一種方法可以解決這種問題,那就是將多張需要批量繪制的紋理圖片合成一張大的紋理圖集。然后使用這張大圖來進行創建CCSpriteBatchNode,這時候創建精靈會默認顯示整張紋理,通過調用CCSprite的setTextureRect()方法,我們可以設置精靈只顯示紋理的一部分區域。

2.3、圖片格式

Cocos2D游戲引擎支持png和jpg格式的紋理圖,但是比較推薦使用的是png格式。因為Cocos2D在加載jpg格式的紋理時,會實時轉換成png格式。這表示加載jpg格式的紋理會比加載png格式的紋理要慢,并且轉換的過程內存也會成倍的增加(3倍)。

2.4、其它方式

除了使用CCSpriteBatchNode來進行批量繪制外,如果在加載紋理時將像素格式設置為16bit深度的話,大概也可以提示10%左右的渲染性能。畢竟,處理32bit深度的位圖需要更多的運算。

三、資源加載/卸載優化

3.1、資源加載

如果打開的游戲場景內部使用資源比較大,那么在構建場景的時候就需要讀取更多的圖片資源到內存中,IO操作本身就是一個耗時的操作,量大的話很容易導致游戲場景跳轉時卡頓。

在場景構建時如果要讀取比較多的資源,我們通常會添加一個loading(加載)場景,然后在loading場景里面做資源的加載操作,等資源全部都加載到內存中的時候,再跳轉到需要打開的場景,訪問內存空間的速度要遠遠高于訪問磁盤空間的速度,所以這時候跳轉場景就會很快速了。

很多程序員在進行資源預加載的時候經常出現程序崩潰的想象,有時候還會問為什么明明做了資源預加載,為什么一進入那個場景就閃退了。

閃退的原因有很多,比如:代碼本身有bug、資源被釋放導致的空指針、內存驟升等。

1、對于代碼本身的bug,我只能說很遺憾慢慢去找吧,改掉就好。

2、資源被釋放導致空指針問題,這個挺常見的,有時候兩個場景有一部分資源是共用的,但是上一個場景結束的時候就給釋放了,導致下一個場景要使用資源的時候方向是個空值(NULL)。對于這種情況,我們需要關注的是兩個場景進行跳轉時生命周期的回調順序,在合適的地方進行釋放應該問題就不大。

3、內存驟升,OS(操作系統)在發現某一個進程如果內存突然間急劇上升,很有可能會將該進程kill掉。

進程會被操作系統殺死,這種事情我們是無力回天了,但是我們可以搞清楚內存為什么會急劇上升。

Cocos2D在加載紋理圖片的時候會先創建CCImage對象,然后根據CCImage對象去創建CCTexture2D紋理對象。所以,這個時候內存的開銷是翻倍的。當創建好CCTexture2D紋理對象后,CCImage才開始釋放。如果加載的紋理圖片格式是jpg的話,由于需要進行格式轉換,內存的開銷就變成是三倍。

當我們在進行資源加載的時候,如果是一張接著一張的加載,有些CCImage對象沒有及時的得到釋放,內存淤積,這時候就會導致內存上升過快。一個有效的解決方案是在加載完一張紋理后,延遲一兩幀再加載下一張紋理。延長加載的時間間隔,讓CCImage得到有效的釋放,內存就不會上漲的那么快。當然,加載的時間也會變得更長,我通常是延遲2幀,loading的時間總體上還是可以接受的。

3.2、資源卸載

進行資源卸載的時機是非常重要的,如果資源被占用,那么遍無法被有效的卸載掉,如果資源在使用前被卸載也很有可能導致空指針問題。通常我們可以在場景跳轉的時候進行一次資源卸載,但是要等舊場景完全被釋放后,新場景又創建結束之后進行資源卸載。這時候由于舊場景被釋放了,占用的資源也可以得到有效的釋放,新的場景又創建完畢,很少出現場景創建過程中讀取紋理失敗的問題。【要了解場景的生命周期】

3.3、分步加載/卸載

對于很多大型的游戲,由于游戲本身資源量太大,導致無法全部加載,這時候可以在合適的地方進行分步加載,這樣游戲打開的速度便會得到有效的提升。同事,可以釋放一些沒有用的資源,合力的利用內存。

但是資源的加載和卸載比較是IO相關的操作,其本身就會耗費較多的性能。在進行加載和卸載的時候會影響到游戲的流暢度,所以在條件允許的情況下,能一次加載的絕不分多次加載,這樣可以保證游戲的流暢度,增強體驗感。

四、安裝包大小優化

游戲安裝包的大小很大程度上決定了游戲的下載量,除非這款游戲真的十分出色。

現在手機的移動流量費都非常的昂貴,每個月的套餐流量又十分的有限,雖然遍地有WIFI。但是包體越大,下載的時間就越久,手機游戲就跟快餐一樣,都是閑暇時間玩個兩三分鐘的那種,如果游戲包很大,下載過程中可能就取消不玩了。

4.1、TinyPNG

在游戲開發完成后,我們可以使用TinyPNG等工具來進行圖片文件的壓縮。TinyPNG有PS插件和網頁在線兩種方案可供選擇,PS插件需要收費,我們可以使用網頁進行壓圖操作,網址是:https://tinypng.com/

TinyPNG可以將圖片壓縮為原來的50%左右,壓縮量非常可觀,而且雖然是有損壓縮,但是壓縮后基本看不出來。

4.2、降低圖片深度

說到這個,我們需要再次提到TexturePaker這款軟件,TexturePaker可以輕易的將圖片設置為16bit深度的格式。這樣圖片占用的空間也會減少一半。

但是使用16bit深度的圖片格式來表示原本32bit的圖片,很多顏色將會丟失,色值便會變成與之相近的另一種顏色。帶有過渡色的圖片便會出現明顯的梯度。

32bit轉成16bit圖,出現顏色梯度

如上圖所示,可以明顯的在花瓣上看到條紋狀的顏色,這顯然不是我們希望看到的事情。好在TexturePaker這個工具支持紋理震蕩算法,我們可以在TexturePaker面板上設置Dithering屬性為“FloydSteinbergAlpha”,這時候就可以看到紋理顯示基本恢復正常了。

設置紋理震蕩后消除梯度

然后將圖片導出,但是要注意的是這時候雖然紋理圖片是16bit的,但是Cocos2D還是會默認將其當成32bit位圖進行加載,除非手動修改紋理的像素格式。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內容

  • 前言 我選擇開發一個游戲有很多原因。我覺得自己是“核心”玩家,過去的大部分時間我都花在玩游戲,自己制作、閱讀和游戲...
    月影檀香閱讀 11,998評論 1 27
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,665評論 25 708
  • 我是一個喜歡淡淡的幸福的人,所以對身邊的人來來回回并沒有表現的很在意。尤其在越長越大的年紀,總覺得自己明明才雙十年...
    iam王木木閱讀 314評論 0 1
  • 當你在做實驗時,遇到了很多問題,這時你是不是特別想找出原因及解決方案啊,那么research gate就是一個很好...
    見龍在田007er2770閱讀 14,761評論 0 0
  • (一)玫瑰色回憶 無論年齡大小,每個人都會經常回憶過往,尤其是那些重要的人、重要的場景和深刻的體驗。 有些回憶是感...
    YuanshanTan閱讀 4,592評論 11 48