天天看點

cocos2d-x 螢幕适配原理分析

cocos2d-x作為著名的cocos2d遊戲開發架構的C++實作者,最近一年發展迅猛。越來越多的app使用它實作快速多平台部署,從最初的ios,android,win32等到新近的html5,實作移動,用戶端到浏覽器全覆寫,不得了~~

cocos2d-x 螢幕适配原理分析

開發移動應用的螢幕适配和愛情一樣是一個從洪荒時代就存在的永恒命題,根本目的是實作在不同裝置上使用者體驗的統一。

cocos2d-x在cocos2d-2.0-x-2.0.4版本之前沒有提供解決的方案,開發者隻能自己解決,其中一些方法見 這裡

從2.0-x-2.0.4開始,勤勞的cocos2d-x團隊終于着手解決這個問題了~贊! 下面用一個執行個體分析一下其實作原理,官方說明文檔見 這裡  

==============================  大家好,我是正文開始之前華麗的分隔線 

cocos2d-x 螢幕适配原理分析

  ===========================

建立一個帶helloworld例子的工程,跑起來是這樣的:

cocos2d-x 螢幕适配原理分析

視窗尺寸為480x320,背景火藍精靈的圖檔原始大小就是480x320,正好鋪滿螢幕。

cocos2d-x 螢幕适配原理分析

我們就從這裡開始變化。。。

首先,模拟分辨率為960x640的螢幕,看看程式會是什麼樣子。

會修改win32下視窗尺寸麼?如果你是從2.0-x-2.0.4之前的版本直接跳過來的,比如我(源自1.0.1-x-0.11.0。。。“源自xxxx”形容酒很有檔次,對于程式設計麼。。還是要與時俱進,改進工作作風密切聯系群衆~),第一反應就是到AppDelegate.cpp裡去找設定win32視窗大小的代碼。

很遺憾,你找不到熟悉的"CC_TARGET_PLATFORM == CC_PLATFORM_WIN32",新版本把設定win32視窗尺寸移到了main.cpp裡面,

如下圖:

cocos2d-x 螢幕适配原理分析

從代碼結構來講,這樣更合理,因為AppDelegate.cpp是與平台無關的程式邏輯入口,裡面不應該還包含大量不同平台的适配代碼。

交給win32自己的main.app去設定,讓上帝的歸于上帝,凱撒的歸于凱撒!

接上述,把eglView->setFrameSize(480,320);  改為eglView->setFrameSize(960, 640);  模拟分辨率為960x640的螢幕,運作效果:

cocos2d-x 螢幕适配原理分析

ok,背景圖尺寸是480x320,在960x640螢幕下自然就填不滿,很合理~

好,需求來了:我們想要的結果是不論在什麼分辨率下,使用者都應該看到背景圖填滿了螢幕!

so,解決方案:

1,使用不同的資源适配不同的螢幕,可以通過判斷螢幕的分辨率來設定加載不同目錄的資源。

2,使用一套資源,在不同的分辨率下比對螢幕進行縮放。

一個個來,先說方案一,既然要為不同分辨率使用不同資源,那就再做一張圖案一樣的火藍精靈背景圖,尺寸為960x640,

用于分辨率為960x640的螢幕。在工程Resources目錄下建立兩個目錄:

cocos2d-x 螢幕适配原理分析

"iphone"目錄存放480x320的背景圖和按鈕圖示,"iphone-retina"存放960x640的背景圖和按鈕圖示。

這兩個目錄名字随意,再看到AppDelegate.cpp,修改代碼如下:

cocos2d-x 螢幕适配原理分析

再運作程式:

cocos2d-x 螢幕适配原理分析

腫麼樣,架構就按照設定找到了960x640的背景圖,螢幕又恢複了不空虛不寂寞的狀态

cocos2d-x 螢幕适配原理分析

這裡要注意:想擷取裝置螢幕實際分辨率需要使用CCSize szFrame = pEGLView->getFrameSize();

而不是之前版本的CCDirector::sharedDirector()->getWinSizeInPixels(); 這個函數另有含義,後文會介紹。

but,面對全世界那麼多的移動裝置,那麼多的分辨率,你hold住麼?就算你hold住,你的美術妹紙們hold住麼?

一種分辨率就出一套比對的美術資源。。“希望你能陪我到地牢到天晃,希望你能陪我到海叫到天啞”。

就算真有以做地老天荒牌遊戲為榮的團隊,出來的安裝包之大,也會讓使用者下載下傳到地老到天荒~

so,這不是個好辦法。

那看看第二種方案,對資源進行縮放,還原Resources目錄的結構:

cocos2d-x 螢幕适配原理分析

現在還是隻有一張480x320的背景圖,怎麼改呢?AppDelegate.cpp裡修改:

cocos2d-x 螢幕适配原理分析

再次運作,amazing!螢幕再次不空虛不寂寞~

cocos2d-x 螢幕适配原理分析

分析:

designResolutionSize是一個新的概念,它讓一切與坐标,尺寸相關的資料徹底擺脫了螢幕分辨率的羁絆,或者說

由架構層來幫開發者完成轉換,開發者需要的隻是設定designResolutionSize。告訴架構你在什麼樣尺寸的場景下

做的資源,比如此例,背景圖原始尺寸480x320,需求是剛好填滿螢幕,那麼就應該告訴架構“嗨,我設計時是以

480x320的螢幕為标準的,你幫我轉轉”,架構就會回答你“放心吧!” 那麼架構究竟如何實作的呢? 跟蹤

pEGLView->setDesignResolutionSize(480, 320, kResolutionNoBorder);

cocos2d-x 螢幕适配原理分析

可以發現,架構是擷取了實際分辨率和開發者designResolutionSize的比例,渲染的時候把圖檔按照這個比例來縮放繪制。

拿本例來說,螢幕960x640,designResolutionSize為480x320,縮放比例為2,那麼原始大小480x320的背景圖,在繪制

時就會x2來繪制,也就是實際繪制成了960x640的大小,這樣就填滿視窗了!

請注意這裡對不同ResolutionPolicy的處理,原理後文會分析。

ok,現在面對480x320和960x640的螢幕,你已經能寫出自動适配的代碼了(其實隻有一句,架構的好處啊~~)

又來了新的需求,“那誰誰,你改一下代碼,程式要能适應ipad2 ”,WTF!好吧,問候歸問候,問題總要解決。

于是你開始想

cocos2d-x 螢幕适配原理分析

“ ipad2分辨率1024x768,就按剛才帥帥凡教我的到main.cpp裡修改”,好,修改為1024x768,看效果:

cocos2d-x 螢幕适配原理分析

ms填滿了,你很滿意,但是不對,右下角的按鈕腫麼快到螢幕外面去了?!仔細一看,不是填滿是填太滿,背景圖都超出螢幕了。

這是腫麼回事呢? 根源在于pEGLView->setDesignResolutionSize(480, 320, kResolutionNoBorder);第三個參數,找到定義:

cocos2d-x 螢幕适配原理分析

講得很清楚了:

kResolutionExactFit:會靠拉伸來填滿螢幕,本例來說背景圖會變形來填充螢幕,因為1024:768=1.3, 480:320=1.5,寬高比不同,圖檔也就無法等比縮放來填滿螢幕,隻能變形了。

kResolutionNoBorder: 看不到黑邊,實際就是寬高等比縮放,但縮放比例取寬比和高比之中大的那一個。

kResolutionShowAll:全部顯示,可以了解為保證内容都顯示在螢幕之内,實際也是寬高等比縮放,但縮放比例取寬比和高比之中小的那一個。

一般來說,我們希望設計時一屏的内容,使用者在實際裝置上也能在一屏内看到,拿本例來說,1024x768分辨率時,右下角的按鈕卻跑到螢幕外去了。看完上面的分析,你應該知道如何解決了: 對了,改變pEGLView->setDesignResolutionSize(480, 320, kResolutionNoBorder);第三個參數為kResolutionShowAll。 ok,看看效果:

cocos2d-x 螢幕适配原理分析

bingo!背景圖填滿了螢幕(水準方向),按鈕緊貼到右下角,可以滿足基本的風格統一要求。

不過縱向上出現黑邊,這個是實際分辨率的寬高比和設計分辨率寬高比不同造成的,無法通過架構層來解決。

隻能交給開發者自己了,比如在代碼裡根據分辨率計算會出現黑邊時,在黑邊填充相應的圖檔等。一些解決方法見 這裡  

setPosition()的變化

之前版本可能已經習慣了CCNode::setPosition(const CCPoint &position);和CCNode::setPositionInPixel(const CCPoint &position);

但在新的版本裡,隻有setPosition(const CCPoint &position); 

這裡傳入的參數不是像素,也和傳統的point有不同,它指的是在designResolutionSize參照下的坐标。

驗證交給你自己來:比如設計分辨率為480x320,設定一個sprite的位置為240,160,在480x320分辨率下會發現它在螢幕正中,

模拟其他分辨率,960x640,1024x768,會發現它依然在螢幕中心,這就可了解240,160這個值跟實際螢幕分辨率已經無關了,

隻和designResolutionSize有關,了解這一點至關重要,是後續開發正确空間感的基礎!

CC_CONTENT_SCALE_FACTOR()的變化

首先enableRetinaDisplay()在新版本裡取消了,将不會有什麼retina裝置上scalefactor為2的說法了,

因為designResolutionSize已經解決了按不同螢幕縮放的問題,是以CC_CONTENT_SCALE_FACTOR();始終傳回1。

cocos2d-x 螢幕适配原理分析

是以新版本裡的定義已經過時了,無須理會。

當然,開發者可以通過CCDirector::sharedDirector()->setContentScaleFactor()來設定contentScaleFactor,這個系數可以了解為

圖檔原始尺寸和designResolutionSize的比值,這個比值将用來繪制圖檔。

如果隻是一套資源按照不同螢幕分辨率縮放,可以不用理會。

getWinSize()的變化

CCDirector::sharedDirector()->getWinSize();   擷取的是designResolutionSize

CCDirector::sharedDirector()->getWinSizeInPixels();  擷取的是getWinSize*contentScaleFactor之後的值,和老版本一樣。

如果contentScaleFactor為1,則這兩個函數傳回的值一樣。 

使用kResolutionNoBorder政策時要注意的

CCSize szVisible = CCDirector::sharedDirector()->getVisibleSize();

CCPoint posVisible = CCDirector::sharedDirector()->getVisibleOrigin();

使用該政策時,因為标準背景圖可能會超出螢幕,是以設定位置時需要已一個可視矩形為基準。

可以這樣了解,szVisible就是你在實際裝置上能看到的有效區域的寬高,posVisible就是這個有效區域的起始坐标,和szVisible構成一個可視矩形,一般來說這個可視矩形是設計分辨率下可視矩形的子集。

總結一下,cocos2d-x新的版本(對于從1.0.1-x-0.11.0上來的人)的确添加了不少新的功能,代碼結構也更加合理,這些都是開發者之福,希望2dxteam繼續加油!

文章轉自  一嗑立撲死 :cocos2d-x螢幕适配原理分析

繼續閱讀