Cocos2d-x 3.1 一步步做螢幕適配
本文並不想講關於螢幕適配的概念或者大道理,如果還不瞭解cocos2d-x螢幕適配的,請先看這篇文章:http://www.cocoachina.com/gamedev/cocos/2014/0516/8451.html。本文有一些內容和圖片是引用這篇文章的。看了那麼多網上關於螢幕適配的文章,還是覺得似懂非懂,所以最好的方法就是自己一步步做好適配。
一、根據螢幕尺寸選擇“最”合適的圖片。
如果根據螢幕尺寸來選擇一樣大小的圖片,那麼美工要哭了,因為對於安卓機,各種各樣的解析度啊,不僅美工要哭了,程式設計師也要哭了。所以,我們只能選擇最合適的圖片,比如320*500解析度和300*480解析度的螢幕可以使用320*480的圖片。
1、在Cocos2d-x自帶的解決方案中就有針對iphone、ipad和ipadhd所做的適配方案,在工程cpp-empty-test有例子。
// AppMacros.h #define DESIGN_RESOLUTION_480X320 0 #define DESIGN_RESOLUTION_1024X768 1 #define DESIGN_RESOLUTION_2048X1536 2 // 要切換設計方案,改變這一行即可 #define TARGET_DESIGN_RESOLUTION_SIZE DESIGN_RESOLUTION_480X320 typedef struct tagResource { cocos2d::Size size; // 尺寸 char directory[100]; // 資源路徑 }Resource; static Resource smallResource = { cocos2d::Size(480, 320), "iphone" }; static Resource mediumResource = { cocos2d::Size(1024, 768), "ipad" }; static Resource largeResource = { cocos2d::Size(2048, 1536), "ipadhd" }; #if (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_480X320) static cocos2d::Size designResolutionSize = cocos2d::Size(480, 320); #elif (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_1024X768) static cocos2d::Size designResolutionSize = cocos2d::Size(1024, 768); #elif (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_2048X1536) static cocos2d::Size designResolutionSize = cocos2d::Size(2048, 1536); #else #error unknown target design resolution! #endif // 480*320的字型大小是24號,根據當前的解析度來修改字型大小 #define TITLE_FONT_SIZE (cocos2d::Director::getInstance()->getOpenGLView()->getDesignResolutionSize().width / smallResource.size.width * 24)
從上面可以看出,cocos2d-x定義了三種大小,分別是iphone(480*320),ipad(1024*768),ipadhd(2048*1536),一般用得比較多的是iphone和ipad。
我們再看一下資原始檔夾,工程->Resource下:
iphone目錄:
ipad目錄:
ipadhd目錄:
也就是說,在這三個資料夾裡面有三套不同大小解析度的圖片,我們之後根據螢幕大小來選擇對應的圖片就行了。
2、實現怎麼根據螢幕大小來選擇圖片。
新建一個工程,再將AppMacros.h檔案拷貝過去。
3、改變視窗尺寸來看效果:// AppDelegate.cpp bool AppDelegate::applicationDidFinishLaunching() { // initialize director auto director = Director::getInstance(); auto glview = director->getOpenGLView(); if(!glview) { glview = GLView::create("My Game"); glview->setFrameSize(480, 320); // 在這裡設定建立視窗的尺寸,手機上這個就不用啦,因為手機有固定的螢幕 director->setOpenGLView(glview); } auto screenSize = glview->getFrameSize(); // 獲取螢幕尺寸 std::vector<std::string> searchPaths; // 這裡是實現的重點,比較螢幕的高和設定的三種適配尺寸的高,選擇合適的圖片 // 然後將對應圖片的路徑新增到搜尋路徑中,那麼cocos2d-x就會到該目錄去尋找圖片 if (screenSize.height > middleResource.size.height) { searchPaths.push_back(largeResource.directory); }else if (screenSize.height > smallResource.size.height) { searchPaths.push_back(middleResource.directory); }else { searchPaths.push_back(smallResource.directory); } FileUtils::getInstance()->setSearchPaths(searchPaths); // turn on display FPS director->setDisplayStats(true); // set FPS. the default value is 1.0/60 if you don't call this director->setAnimationInterval(1.0 / 60); // create a scene. it's an autorelease object auto scene = HelloWorld::createScene(); // run director->runWithScene(scene); return true; }
視窗尺寸500*300:
因為高300小於320,所以使用480*320的圖片。這時候看到的是左右有黑邊,上下被截了一點。沒事,下面會講怎麼解決。
視窗尺寸700*300:
還是用480*320解析度的,都是300的錯。
視窗尺寸800*480:
這次用的是1024*768的了,因為320<480<768。
在500*300尺寸中我們看到圖片左右因為不夠寬而出現黑邊,而上下因為太大了而被截取了一部分,那麼要怎麼解決這個問題呢?往下看。
二、圖片與螢幕“完美”融合
為了使圖片能與螢幕“完美”融合,Cocos2d-x提供了一組相關的介面和5種解析度適配的策略。
首先了解一下三種解析度:
資源解析度:也就是圖片解析度,下面寬Resource Width簡寫為RW,高Resource Height簡寫為RH。
設計解析度:也就是我們設定區域的解析度,下面寬Design Width簡寫為DW,高Design Height簡寫為DH。
螢幕解析度:也就是視窗解析度,下面寬Screen Width簡寫為SW,高Screen Height簡寫為SH。
Cocos2d-x的圖片顯示有下面兩個過程:
從資源解析度到設計解析度,從設計解析度到螢幕解析度。
這個過程就是:
1、先選定目標的設計解析度,在AppMacros.h中我們定義了三種解析度,分別是480*320,1024*768,2048*1536:
預設選中的是480*320:
2、從資源解析度到設計解析度
通過setContentScaleFactor()函式來縮放圖片的解析度,以適應設計解析度的大小。這個函式的引數不是通過資源寬/螢幕寬、資源高/螢幕高得來的,而是通過資源寬/設計解析度寬、資源高/設計解析度高得來的。這樣我們就可以不關注螢幕尺寸,先根據現有的資源跟選好的設計解析度來做好適配。
在上面800*480尺寸的圖中可以看到,圖片四邊都被截取了,原因就是沒有做好圖片的縮放,接下來我們先用setContentScaleFactor()來做圖片縮放。
設計解析度選擇的是480*320,視窗解析度480*321,這樣用的就是1024*768解析度的圖片了:
if (screenSize.height > middleResource.size.height)
{
searchPaths.push_back(largeResource.directory);
director->setContentScaleFactor(largeResource.size.height/designResolutionSize.height);
}else if (screenSize.height > smallResource.size.height)
{
searchPaths.push_back(middleResource.directory);
// 縮放因子是資源寬/設計解析度寬
director->setContentScaleFactor(middleResource.size.height/designResolutionSize.height);
}else
{
searchPaths.push_back(smallResource.directory);
director->setContentScaleFactor(smallResource.size.height/designResolutionSize.height);
}
效果:
用高度比作為內容縮放因子,保證了背景資源的垂直方向在設計解析度範圍內的全部顯示。
修改縮放因子為資源寬/設計寬:
// 縮放因子是資源寬/設計解析度寬
director->setContentScaleFactor(middleResource.size.width/designResolutionSize.width);
用寬度比作為內容縮放因子,保證了背景資源的水平方向在設計解析度範圍內的全部顯示。
可以參考一下這張圖,我的是橫屏的,這張圖畫的是豎屏的,不過原理一樣:
3、從設計解析度到螢幕解析度
設計解析度是我們自定義解析度方案,圖片根據設計解析度做好了縮放效果了,如果跟螢幕解析度適配,說白了就是一廂情願。最後一步就是使用setDesignResolutionSize()函式來實現設計解析度到螢幕解析度的完美適配了:
void GLViewProtocol::setDesignResolutionSize(float width, // DW
float height, // DH
ResolutionPolicy resolutionPolicy) // 適配策略
五種適配策略:
enum class ResolutionPolicy
{
EXACT_FIT,
NO_BORDER,
SHOW_ALL,
FIXED_HEIGHT,
FIXED_WIDTH,
UNKNOWN,
};
先看不使用適配策略的情況,在第2中,設定視窗解析度為960*640:
接著,我們使用setDesignResolutionSize()函式來適配設計解析度和螢幕解析度:
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::EXACT_FIT);
效果:
這時候就是我們想要的效果了。
上面說到共有五種解析度適配的策略,其實就是從設計解析度適配到螢幕解析度時,圖片拉伸的策略:
1、ResolutionPolicy::SHOW_ALL
螢幕寬、高分別和設計解析度寬、高計算縮放因子,取較(小)者作為寬、高的縮放因子。
保證了設計區域全部顯示到螢幕上,但可能會有黑邊。
2、ResolutionPolicy::EXACT_FIT
螢幕寬 與 設計寬比 作為X方向的縮放因子,螢幕高 與 設計高比 作為Y方向的縮放因子。
保證了設計區域完全鋪滿螢幕,但是可能會出現影象拉伸。
3、ResolutionPolicy::NO_BORDER
螢幕寬、高分別和設計解析度寬、高計算縮放因子,取較(大)者作為寬、高的縮放因子。
保證了設計區域總能一個方向上鋪滿螢幕,而另一個方向一般會超出螢幕區域。
如圖:
ResolutionPolicy::NO_BORDER
是之前官方推薦使用的方案,他沒有拉伸影象,同時在一個方向上撐滿了螢幕,
但是新加入的兩種策略將撼動ResolutionPolicy::NO_BORDER的地位。
ResolutionPolicy::FIXED_HEIGHT和ResolutionPolicy::FIXED_WIDTH
都是會在內部修正傳入設計解析度,以保證螢幕解析度到設計解析度無拉伸鋪滿螢幕。
4、ResolutionPolicy::FIXED_HEIGHT
保持傳入的設計解析度高度不變,根據螢幕解析度修正設計解析度的寬度。
適合高方向需要撐滿,寬方向可裁減的遊戲,結合setContentScaleFactor(RH/DH)使用。
5、ResolutionPolicy::FIXED_WIDTH
保持傳入的設計解析度寬度不變,根據螢幕解析度修正設計解析度的高度。
適合寬方向需要撐滿,高方向可裁減的遊戲,結合setContentScaleFactor(RW/DW)使用。
如圖:
螢幕適配的就講到這裡了,由於本人口才不好,所以有些地方可能表達不夠清晰,請見諒。
網上講螢幕適配這方面的文章一搜一大把,但都是理論知識,個人覺得最好的學習方法就是去做個demo,一步步做,看看效果如何,這樣才能掌握。