-
Notifications
You must be signed in to change notification settings - Fork 43
cocos2d x 3.3 014 屏幕适配
- 我在跑cpp-empty-test例子的时候注意到一点: 图片上标的分辨率的字眼为何没显示完整? 于是深入挖掘了下, 先从官网找了两篇不错的文章, 然后自己修改cpp-empty-test里相关代码测试。 特记录下心得。
- 问题本质是一套基于某特定分辨率设计如何在众多不同分辨率设备上的显示问题。是个宽高的缩放问题。
- 要不要保持宽高比例进行缩放?保持:不保持
- 缩放的比例是多少合适?
- 设计分辨率,可以天马行空,要多大有多大
- 资源分辨率(游戏背景资源分辨率),理想情况是和设计分辨率一样,这样省得各种计算。但既然是资源,用它就有开销,所以实际情况和设计分辨率会有差异。
- 屏幕分辨率,即各种设备的真实分辨率。我们的目的是要自动适配,那在使用过程中是不需要考虑实际的分辨率的。
- 定义设计分辨率
static cocos2d::Size designResolutionSize = cocos2d::Size(宽度, 高度);
- 资源分辨率到设计分辨率的映射比例
director->setContentScaleFactor()
和资源的选取setSearchPaths
- 设计分辨率到屏幕分辨率的映射策略(是否保持款高比+缩放比例)ResolutionPolicy
- 资源选择setSearchPaths+资源分辨率到设计分辨率的映射
director->setContentScaleFactor(比例), 比例一般取值MAX(resource.size.height/designResolutionSize.height, resource.size.width/designResolutionSize.width) 或者MIN(resource.size.height/designResolutionSize.height, resource.size.width/designResolutionSize.width)
- 设计分辨率到屏幕分辨率的映射
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::XXX);
,最后参数选择适当的ResolutionPolicy值
- 前提: 设计分辨率和资源分辨率成正比(先屏蔽掉资源分辨率到设计分辨率映射的干扰)
//定义设计分辨率,和资源分辨率相等.
- designResolutionSize = cocos2d::Size(2048, 1536);
//设置资源分辨率到设计分辨率的映射比例(此时值=1) 2. searchPath.push_back(largeResource.directory); director->setContentScaleFactor(MAX(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width)); FileUtils::getInstance()->setSearchPaths(searchPath);
//设计分辨率到屏幕分辨率的映射策略 3. glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::SHOW_ALL);
* 调整代码3中ResolutionPolicy的取值,得如下结论(TODO log显示fixed_width, fixed_height时, getVisibleSize有变化)
* ResolutionPolicy::SHOW_ALL, 保持宽高比例,图片完整显示,宽度方向两侧有黑边
TITLE_FONT_SIZE=102.400000) getVisibleSize(w=2048.000000, h=1536.000000) getWinSize(w=2048.000000, h=1536.000000) frameSize(w=960.000000, h=640.000000) getWinSizeInPixels(w=2048.000000, h=1536.000000) designResolutionSize(w=2048.000000, h=1536.000000) MAX=1.000000) MIN=1.000000)
* ResolutionPolicy::NO_BORDER,保持宽高比例,图片宽度方向完整显示,高度方向超出显示不全
TITLE_FONT_SIZE=102.400000) getVisibleSize(w=2048.000000, h=1365.333374) getWinSize(w=2048.000000, h=1536.000000) frameSize(w=960.000000, h=640.000000) getWinSizeInPixels(w=2048.000000, h=1536.000000) designResolutionSize(w=2048.000000, h=1536.000000) MAX=1.000000) MIN=1.000000)
* ResolutionPolicy::FIXED_WIDTH,保持宽高比例,图片宽度方向完整显示,高度方向超出显示不全,效果类NO_BORDER
TITLE_FONT_SIZE=102.400000) getVisibleSize(w=2048.000000, h=1366.000000)//h变化了~~~!!! getWinSize(w=2048.000000, h=1366.000000)//h变化了 frameSize(w=960.000000, h=640.000000) getWinSizeInPixels(w=2048.000000, h=1366.000000)//h变化了 designResolutionSize(w=2048.000000, h=1536.000000) MAX=1.000000) MIN=1.000000)
* ResolutionPolicy::FIXED_HEIGHT,保持宽高比例,图片完整显示,宽度方向两侧有黑边,效果类SHOW_ALL
TITLE_FONT_SIZE=115.200000) getVisibleSize(w=2304.000000, h=1536.000000)//w变化了~~~!!! getWinSize(w=2304.000000, h=1536.000000)//w变化了 frameSize(w=960.000000, h=640.000000) getWinSizeInPixels(w=2304.000000, h=1536.000000)//w变化了 designResolutionSize(w=2048.000000, h=1536.000000) MAX=1.000000) MIN=1.000000)
* ResolutionPolicy::EXACT_FIT,不保持宽高比例,就是SHOW_ALL有黑边的方向被拉伸
TITLE_FONT_SIZE=102.400000) getVisibleSize(w=2048.000000, h=1536.000000) getWinSize(w=2048.000000, h=1536.000000) frameSize(w=960.000000, h=640.000000) getWinSizeInPixels(w=2048.000000, h=1536.000000) designResolutionSize(w=2048.000000, h=1536.000000) MAX=1.000000) MIN=1.000000)
### 初步理解setContentScaleFactor
* 前提: 设计分辨率和屏幕分辨率成正比(先屏蔽掉设计分辨率到屏幕分辨率映射的干扰)
- 设计分辨率=屏幕分辨率
static cocos2d::Size designResolutionSize = cocos2d::Size(960, 640);
- ResolutionPolicy取值EXACT_FIT
* 给setContentScaleFactor传MIN(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width), 显示效果,宽方向刚好全显,高超出,效果类NO_BORDER
* 给setContentScaleFactor传MAX(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width), 显示效果,高方向刚好全显,宽全显但有黑边,效果类SHOW_ALL
* 给setContentScaleFactor传MIN*2.0, 显示效果,图片宽高变为原来的1/2了,关闭按钮和fps位置保持了不变。
* 给setContentScaleFactor传MIN*0.5, 显示效果,图片宽高变为原来的2倍了,画面仅显示了1/2的宽高, 关闭按钮和fps位置保持了不变。
* 其他值自己感受试试
# 一个简化的数学模型
* 来个理想情况1,资源分辨率=设计分辨率,屏幕分辨率不同,来适配
* eg. 资源分辨率=设计分辨率=1 X 0.5, 屏幕分辨率=1 X 0.8
* ResolutionPolicy取EXACT_FIT时,设计分辨率宽不变,高0.5被缩放到0.8,宽高比变化会导致变形
* ResolutionPolicy取NO_BORDER时,高要从0.5缩放到0.8, 然后宽做等比缩放,最终宽=1*(0.8/0.5),无黑边,有裁剪
* ResolutionPolicy取SHOW_ALL时, 这个大小刚好放入实际屏幕,高度方向有黑边
* ResolutionPolicy取FIXED_HEIGHT时,设计分辨率的高0.5缩放到0.8后, 宽度做等比缩放, 确保高度方向全显(TODO,right?这么理解貌似和NO_BORDER效果一样)
* ResolutionPolicy取FIXED_WIDTH时, 设计分辨率的宽1缩放到1, 高度做等比缩放, 确保宽度方向全显(TODO,right?这么理解貌似和SHOW_ALL效果一样))
* 来个理想情况2,资源分辨率不同,设计分辨率=屏幕分辨率,来适配
* eg. 资源分辨率=1 X 0.5, 设计分辨率=屏幕分辨率=1 X 0.8
* 给setContentScaleFactor传MIN(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width)=5/8, 显示效果,高方向刚好全显,宽超出
* 给setContentScaleFactor传MAX(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width)=1, 显示效果,宽方向刚好全显,高全显但有黑边
# 最佳实践,暂且这么理解
* 在AppMacros.h有这样提到
[Note] Normally, developer just need to define one design resolution(e.g. 960x640) with one or more resources. */
* 为什么一般要一个设计分辨率对应多套资源呢? 原因在与图片缩放比例过大会失真的比较严重,导致看起来比较模糊等。 故一般提供多套资源, 根据实际选择最接近真实分辨率的资源,这样图片的缩放比例将是最小, 失真也最小。用法见cpp-empty-test(一种实现方法,在资源的选择上不是最优)。
# 小结
* 到屏幕的适配cocos只关心设计分辨率和适配策略ResolutionPolicy,各种策略的效果见上面实验。
* 但资源的分辨率可能会和设计分辨率不一样, 那怎么用资源的大小来填充设计分辨率, 那就缩放咯, 各种缩放参数的效果见上面实验。
* 为避免资源缩放过大导致失真, 一般会提供几套分辨率的资源。 在使用时选择最接近屏幕尺寸的资源使用。
# 疑惑
* cocos为何这样设计呢? 先资源的宽高到设计的宽高缩放,再设计的宽高到实际屏幕宽高的适配策略。
* 可不可以直接是资源的宽高到屏幕宽高的适配策略? 个人初步感觉可以, 尤其是setContentScaleFactor的参数取MAX MIN时和NO_BORDER SHOW_ALL没区别, 当然EXACT_FIT 更没得说了。
* FIXED_HEIGHT FIXED_WIDTH 通过上面看会修改getWinSize getWinSizeInPixels, 到底有什么影响呢?
# 后记
* 针对上面疑惑的1,为何这么设计呢? 主要是略过屏幕分辨率,一切以设计分辨率为参考(若设计分辨率和资源分辨率一样或者等比,也可以说是以资源分辨率来参考)
* 针对上面疑惑的2,个人依然这么认为。
* 针对上面疑惑的3,即FIXED_HEIGHT FIXED_WIDTH 和NO_BORDER的区别,区别就在FIXED_HEIGHT FIXED_WIDTH的可见区域起点Director::getInstance()->getVisibleOrigin() = (0.000000, 0.000000),而NO_BORDER的可见区域起点却不一定等于(0.000000, 0.000000)。 所以在测试代码中有个细节,放置控件的时候有这样的(+origin)位移细节```closeItem->setPosition(origin + Vec2(visibleSize) - Vec2(closeItem->getContentSize() / 2));```
* 代码验证
-
设计分辨率(和资源分辨率一样) static cocos2d::Size designResolutionSize = cocos2d::Size(480, 320);
-
资源分辨率 searchPath.push_back(smallResource.directory);
-
在场景层中增加如下代码(想要的效果是在可见区域的四个角落和每条边的中间画一个图标) log("visibleSize, (%f, %f)", visibleSize.width, visibleSize.height); log("origin, (%f, %f)", origin.x, origin.y); { auto sprite = Sprite::create("CloseSelected.png"); sprite->setPosition(ccp(0, 0)); this->addChild(sprite); } { auto sprite = Sprite::create("CloseSelected.png"); sprite->setPosition(ccp(0, visibleSize.height)); this->addChild(sprite); } { auto sprite = Sprite::create("CloseSelected.png"); sprite->setPosition(ccp(0, visibleSize.height / 2)); this->addChild(sprite); } { auto sprite = Sprite::create("CloseSelected.png"); sprite->setPosition(ccp(visibleSize.width, visibleSize.height)); this->addChild(sprite); } { auto sprite = Sprite::create("CloseSelected.png"); sprite->setPosition(ccp(visibleSize.width, 0)); this->addChild(sprite); } { auto sprite = Sprite::create("CloseSelected.png"); sprite->setPosition(ccp(visibleSize.width / 2, 0)); this->addChild(sprite); } { auto sprite = Sprite::create("CloseSelected.png"); sprite->setPosition(ccp(visibleSize.width / 2, visibleSize.height)); this->addChild(sprite); } { auto sprite = Sprite::create("CloseSelected.png"); sprite->setPosition(ccp(visibleSize.width, visibleSize.height / 2)); this->addChild(sprite); }
-
调整ResolutionPolicy的取值, 效果图如下
- SHOW_ALL
- EXACT_FIT
- NO_BORDER
- FIXED_HEIGHT
- FIXED_WIDTH
- 发现没,NO_BORDER时,周围的图标都有y方向都有下移, 因为他的可见区域真正可见的起始点不是0。通过
+Director::getInstance()->getVisibleOrigin()
能得以修正。
Just build something.