cocos2d-x是一款衆所周知的跨平臺的遊戲開發引擎。由於其跨平臺的特性。多分辨率支持也天然就有其需求。html
所以。在某一次更新中(抱歉,筆者已經忘了是哪次更新了),cocos2d-x加入了一個新的方法。可以很簡便地讓cocos2d依據屏幕尺寸的大小作自適配。app
方法名:iphone
virtual void setDesignResolutionSize(float width, float height, ResolutionPolicy resolutionPolicy);
該方法所傳的參數中,前兩個參數width、height,指的是開發人員在設計界面時默認設計的尺寸。好比:開發人員在設計界面時以iphone5爲準,則width和height就是568*320;如果以iphone4爲準。則width和height就是480*320;以此類推。ide
第三個參數resolutionPolicy指的是cocos2d在縮放時需要遵照的規則。ResolutionPolicy這個本身定義結構例如如下:post
enum ResolutionPolicy { // The entire application is visible in the specified area without trying to preserve the original aspect ratio. // Distortion can occur, and the application may appear stretched or compressed. kResolutionExactFit, // The entire application fills the specified area, without distortion but possibly with some cropping, // while maintaining the original aspect ratio of the application. kResolutionNoBorder, // The entire application is visible in the specified area without distortion while maintaining the original // aspect ratio of the application. Borders can appear on two sides of the application. kResolutionShowAll, kResolutionUnKnown, };
經過凝視可以看出:this
kResolutionExactFit是指cocos2d縮放的時候不考慮畫面失真,直接用畫面填充滿整個屏幕spa
kResolutionNoBorder是指cocos2d縮放的時候儘可能頂滿畫面,假設所以有超出畫面的部分,就會把超出的部分切除掉(舉例來講:假設設計大小是568*320,在480*320大小的屏幕上自適配的時候,就會把寬度超出的部分切除)debug
kResolutionShowAll是指cocos2d縮放的時候顯示所有的畫面,假設有填不滿屏幕的地方就會顯示黑條。設計
這三種規則各有優缺點,詳細使用哪一種規則需要考量項目的需要進行合理的選擇。調試
然而。需要特別注意的一點是:setDesignResolutionSize和enableRetina這兩個方法是不可以同一時候使用的。
這即意味着使用自適配的時候是不可以作高清版的。
假設查看cocos2d-x源碼。可以看到在setDesignResolutionSize方法中有一句代碼:
CCAssert(m_bIsRetinaEnabled == false, "can not enable retina while set design resolution size!");
在下以爲這是因爲高清模式下圖片資源都是進行了縮小的,所有的座標都是定義的point,而不是pixel。所以高清模式和自適配可能有某些衝突存在。
(以上僅僅是筆者的推測,不靠譜勿怪)
總之,假設想要使用自適配。就必須在項目一開始就放棄高清。假設要作高清版,眼下看來就僅僅能本身依據屏幕尺寸的比例變化設置setContentScaleFactor,這一部分的設置方法這裏就不展開了。
另外,筆者在剛開始使用自適配功能時,誤覺得開發時要把UI元素的位置座標和大小都寫成相對於屏幕大小的必定比例。好比:
CCSprite* avatarSprite = CCSprite::create("avatar.png"); avatarSprite->setPosition(ccp(winSize.width * 0.000878, winSize.height * 0.653125)); addChild(avatarSprite);
但實際上這是沒有必要的。
自適配功能是直接調整整個CCDirector的畫布大小,所以不論什麼加入到CCDirector中的元素都會被縮放對應的比例。沒有必要再特地將座標寫成相對屏幕比例的模式。
如下筆者將分享一下在使用自適配功能的時候遇到的一個問題,即CCListView在多分辨率模式下可能出現的被過多地切除一部份內容的問題。
首先先介紹下筆者發現問題時的背景:當時筆者是在實現一款跨平臺的遊戲的當中一個界面,該遊戲的畫面是依照iphone5的低清版設計。DesignResolutionSize設置的是568*320。在安裝到iphone5上時一切正常。但是隨後,在安裝到iphone4機器上進行調試時,發現畫面上所有的CCListView都被切除了左邊的一部份內容。
由於在iphone5上一切正常。在iphone4上畫面被切除了一部分。所以筆者立刻懷疑是CCListView與setDesignResolutionSize之間有某些衝突。
經過debug和log。最後將問題鎖定到了CCListView類的visit方法。
方法的源碼例如如下:
void CCListView::visit(void) { if (!m_pListViewParent) { CCRect rectSelf; float factor = CC_CONTENT_SCALE_FACTOR(); rectSelf.origin = convertToWorldSpace(CCPoint(0,0)); rectSelf.origin.x *= factor; rectSelf.origin.y *= factor; rectSelf.size = this->getContentSize(); rectSelf.size.width *= factor; rectSelf.size.height *= factor; glScissor((GLsizei)rectSelf.origin.x, (GLsizei)rectSelf.origin.y, (GLsizei)rectSelf.size.width , (GLsizei)rectSelf.size.height); glEnable(GL_SCISSOR_TEST); } CCLayerColor::visit(); if (!m_pListViewParent) { glDisable(GL_SCISSOR_TEST); } }
這段代碼中調用了一個方法:glScissor。這種方法是框定了CCListView將會顯示在屏幕上的範圍。
而由於在使用自適配模式。對CC_CONTENT_SCALE_FACTOR沒有作不論什麼改動,所以這個框出來的範圍是相應於DesignResolutionSize設定的原始設計畫面大小的。而在屏幕尺寸發生了變化。整個CCDirector被縮放的狀況下。這個rectSelf卻沒有作不論什麼改變,因此就致使了上述的被切除一部分的問題。
隨後,筆者經過搜索。發現已經有人遇到了同一個問題。而且還提供了修復的方法:http://www.cocos2d-x.org/boards/18/topics/14464
簡單講就是,用CCEGLView::sharedOpenGLView()->setScissorInPoints方法替換glScissor方法。其餘不論什麼地方都不用變。
改動好之後在iphone4和5上調試都沒問題,所以這個bug自己可以算是修復了。
PS:由於對這種方法能夠奏效感到好奇,筆者查看了setScissorInPoints方法的源文件。代碼例如如下:
void CCEGLViewProtocol::setScissorInPoints(float x , float y , float w , float h) { glScissor((GLint)(x * m_fScaleX + m_obViewPortRect.origin.x), (GLint)(y * m_fScaleY + m_obViewPortRect.origin.y), (GLsizei)(w * m_fScaleX), (GLsizei)(h * m_fScaleY)); }
可以看出這種方法內部仍然是調用了glScissor方法,但是傳遞的參數則考考慮到在屏幕尺寸的變化,所以,爲了確保這種方法不切割過多CCListView內容。
其餘,在project搜索glScissor發現CCScrollView這個方法也被稱爲,假定的使用CCScrollView建議同時更換的源代碼glScissor方法。