1. 程式人生 > >Cocos2d-x 3.1 一步步做螢幕適配

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檔案拷貝過去。

// 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,一步步做,看看效果如何,這樣才能掌握。