本文並不想講關於屏幕適配的概念或者大道理,如果還不瞭解cocos2d-x屏幕適配的,請先看這篇文檔:《Cocos2d-x 多分辨率適配完全解析》。本文有一些內容和圖片是引用這篇文章的。看了那麼多網上關於屏幕適配的文章,還是覺得似懂非懂,所以最好的方法就是自己一步步做好適配。
一、根據屏幕尺寸選擇“最”合適的圖片
如果根據屏幕尺寸來選擇一樣大小的圖片,那麼美工要哭了,因爲對於安卓機,各種各樣的分辨率啊,不僅美工要哭了,程序員也要哭了。所以,我們只能選擇最合適的圖片,比如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文件拷貝過去。
// 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;
}
3、改變窗口尺寸來看效果
窗口尺寸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,一步步做,看看效果如何,這樣才能掌握。