1. 程式人生 > >再談cocos2d-x螢幕適配

再談cocos2d-x螢幕適配

一直以來,在 cocos2d-x 平臺中如何用一套資源適配全螢幕都是每個程式的夢想。隨手百度都可以搜尋到很多關於 cocos2dx 適配的文章,但是看完之後的感覺仍然是不知道如何具體操作,所以自己參考網上其他人的帖子,並結合 cocos2dx 原始碼,自己驗證了一番在此做個總結。如有不正確的地方請大家提出討論。

首先是做 Android 的同學們先暫時忘掉 dpi 的概念,無論是幾寸屏多少 dpi,在cocos2dx 裡面只關心畫素就可以了。

cocos2dx裡面提供幾種概念,FrameSize/WinSize/WinPixel/VisibleSize/VisibleOrigin,那麼就一次性都輸出出來看看這些值都是代表什麼。

測試環境

iPhone6 (640x1136)

iPhone6 plus (1242x2208)

Nexus4 (768x1184)

在 iPhone6的模擬器上執行獲得如下結果

cocos2d: FrameSize width = 640.000000  height = 1136.000000

cocos2d: WinSize width = 640.000000  height = 1136.000000

cocos2d: WinPixel width = 640.000000  height = 1136.000000

cocos2d: VisibleSize width = 640.000000  height = 1136.000000

cocos2d: VisibleOrigin x = 0.000000  y = 0.000000

在 Nexus4上輸出結果如下


然後,我設定了一下

auto director = Director::getInstance();

auto glview = director->getOpenGLView();

glview->setDesignResolutionSize(1242.0f, 2208.0f, ResolutionPolicy::FIXED_HEIGHT);

再次輸出上面那些值

cocos2d: frameSize width = 640.000000  height = 1136.000000

cocos2d: WinSize width = 1244.000000  height = 2208.000000

cocos2d: winPixel width = 1244.000000  height = 2208.000000

cocos2d: visibleSize width = 1244.000000  height = 2208.000000

cocos2d: visibleOrigin x = 0.000000  y = 0.000000


所以我們得出一個結論 FrameSize 是螢幕的真實尺寸,WinSize = WinPixel = VisibleSize, 受我們設定的 DesignResolutionSize影響。這裡沒有對 WinSize 及 VisibleSize 做更多的測試,通過設定可能會存在不一致的情況,這裡先不對這些情況討論。

接下來我們看一下 ResolutionPolicy::FIXED_HEIGHT 相關的設定。

找到原始碼:void GLView::updateDesignResolutionSize()函式

_scaleX = (float)_screenSize.width / _designResolutionSize.width;

_scaleY = (float)_screenSize.height / _designResolutionSize.height;

        if (_resolutionPolicy == ResolutionPolicy::NO_BORDER)

        {

_scaleX = _scaleY = MAX(_scaleX, _scaleY);

        }

elseif (_resolutionPolicy == ResolutionPolicy::SHOW_ALL)

        {

_scaleX = _scaleY = MIN(_scaleX, _scaleY);

        }

elseif ( _resolutionPolicy == ResolutionPolicy::FIXED_HEIGHT) {

            _scaleX = _scaleY;

_designResolutionSize.width = ceilf(_screenSize.width/_scaleX);

        }

elseif ( _resolutionPolicy == ResolutionPolicy::FIXED_WIDTH) {

            _scaleY = _scaleX;

_designResolutionSize.height = ceilf(_screenSize.height/_scaleY);

        }

通過分析原始碼,得到如下結論:

ResolutionPolicy::EXACT_FIT--全屏,如果螢幕比例跟設計尺寸的比例不相等,則圖片會被變形拉伸。

ResolutionPolicy::NO_BORDER--無黑邊模式,如果螢幕比例跟設計尺寸的比例不相等,則一定有一個方向被裁剪。

ResolutionPolicy::SHOW_ALL--全屏模式,如果螢幕比例跟設計尺寸的比例不相等,則一定有一個方向顯示黑邊。

ResolutionPolicy::FIXED_HEIGHT--按高度適配,果螢幕比例跟設計尺寸的比例不相等,則橫向要麼被裁剪,要麼出黑邊。

ResolutionPolicy::FIXED_WIDTH--按寬度適配,果螢幕比例跟設計尺寸的比例不相等,則縱向要麼被裁剪,要麼出黑邊。

以上都是廢話,人家註釋裡寫的清清楚楚。

說了這麼多最想知道的問題還是沒有得到解答,我該用哪個模式?設計解析度應該設定多大?美術應該切多大的圖?

下面根據我個人的理解,對這幾個問題一一解答。

1,模式的選擇。

如果能忍受黑邊,推薦 SHOW_ALL模式。這樣美術最省力,嚴格按照DesignResolutionSize畫就可以了。

如果能忍受變形拉伸,就直接EXACT_FIT,但是我個人是不接受變形拉伸的。朋友之前的一款遊戲採用這個模式,素材在設計的時候比例介於16:9跟4:3之間,所以拉伸的時候變形也不是很嚴重,大家可以參考。

如果你採用剩下的3種模式一定要提前跟美術溝通,因為可能會產生裁剪。

NO_BORDER模式由於不確定哪個方向產生裁剪,美術同學可能會瘋掉。需要兩個方向都預留出來一部分內容,即便被裁剪掉也不影響整體效果即可。

如果採用 FIEXD_HEIGHT模式,請美術同學在橫向上預留出一部分內容以防被裁剪。

如果採用 FIEXD_WIDTH 模式,請美術同學在縱向上預留出一部分內容以防被裁剪。

2,DesignResolutionSize。

這個設計解析度直接影響包的尺寸,所以要慎重。



蘋果還是很良心的,6跟6p 的橫縱比是相等的,所以只要DesignResolutionSize的橫縱比是0.563,選任何上面一個模式都是全屏不變形無黑邊無裁剪

這次提供的素材是1242x2208,顯示到 Nexus4的時候兩側出現了黑邊(setDesignResolutionSize(1242.0f2208.0fResolutionPolicy::FIXED_HEIGHT);)

原因是這個模式下 WinSize是1433,2208。

關於如何切圖,

先根據遊戲的型別及包尺寸的要求,決定適配模式。程式同學請事先同美術溝通好,再決定一個DesignResolutionSize,核心的元素需要畫在這個尺寸之內。另外根據模式再在需要的方向上留一定的被裁剪空間。

FIXED_HEIGHT 模式素材提供的橫縱比略大一些,兩側留一些被裁剪的空間,就可比較好的適配各種螢幕。setDesignResolutionSize 函式的第一個引數只要不為0即可,計算的時候會被無視掉。

FIXED_WIDTH 模式素材提供的橫縱比略大一些,上下預留被裁剪的空間。setDesignResolutionSize 函式的第二個引數只要不為0即可,計算的時候會被無視掉。

SHOW_ALL最簡單,美術不需要預留,嚴格按DesignResolutionSize切圖,請容忍黑邊。

NO_BORDER,美術兩個方向都要預留被裁剪的空間。

EXACT_FIT,橫縱比取折衷大小,容忍變形。

採用以上的方法之後,圖片應該不需要在程式碼中二次縮放,因為 cocos2dx 已經替你進行縮放了。

那麼程式還需要解決一個問題,介面元素與元素之間的距離。

FIXED_HEIGHT 模式下縱向位置固定為設定的 DesignResolutionSize,所以請美術直接給出高度就可以直接使用,不論上邊距還是下邊距不需要適配。但是橫向上畫素數量不固定,請以螢幕中軸做參考向兩側距離適配。FIXED_WIDTH 同理橫向不需要特別適配,縱向以中軸做參考向兩側適配。

SHOW_ALL/NO_BORDER/EXACT_FIT 三個模式橫向縱向最好都以中軸做參考適配。當然有些時候按鈕跟背景圖片位置不關聯,這個時候只要保證不出螢幕就可以了。

由於時間關係沒有進行更多機型的適配測試,難免有遺漏或者錯誤的地方,歡迎大家把自己實際測試的情況也分享下。