[原创]cocos2d-x研习录-第三阶 多分辨率适配器

时间:2023-12-16 18:36:32

在移动终端(智能手机)平台下开发游戏一般都会涉及到屏幕多分辨率适配问题,原因是手机款式多种多样,不同的款式存在有不同的尺寸,即使尺寸相同又可能存在不同的分辨率。

手机屏幕尺寸:指手机屏幕对角线长度。

[原创]cocos2d-x研习录-第三阶 多分辨率适配器

手机分辨率:指屏幕上横、纵的总象素点数。分辨率越高,即总象素点数越多,屏幕显示效果越好。              [原创]cocos2d-x研习录-第三阶 多分辨率适配器

上面我们介绍了手机尺寸和分辨率的概念,结论是手机屏幕显示效果是由尺寸和分辨率决定的。相同尺寸不同分辨率手机,分辨率越高显示效果越好;相同分辨率不同尺寸的手机,尺寸越大显示效果越差。

有了这两个概念,我们要开始探讨多分辨率适配问题。

什么是多分辨率适配问题呢?举例说明一下。

(1)有两款手机,屏幕尺寸相同,但分辨率不同;手机A分辨率为320*480,手机B分辨率为640*960。现在我要将一张分辨率为320*480的图片显示到两部手机屏幕上,结果将会如何呢?

答案:手机A会全屏显示图片,手机B只有四分之一屏幕会显示图片。

(2)有两款手机,屏幕分辨率都为320*480,但尺寸不同;手机A尺寸是5寸屏,手机B尺寸是3寸屏。现在我要将一张分辨率为320*480的图片显示到两部手机屏幕上,结果将会如何呢?

答案:手机A和手机B都全屏显示图片。

由上两个例子可以知道,多分辨率适配问题只与手机屏幕分辨率有关,与屏幕尺寸无关。如果所有手机都采用相同分辨率,那么将不存在多分辨率适配问题。但事实上,这肯定是不可能的。

所以,我们在开发过程中形容手机屏幕大小,可以忽略屏幕的尺寸,只使用分辨率。

那么我们解决多分辨率适配问题的目的是什么呢?根本目的当然是实现不同分辨率设备上用户体验的统一。换句话说,就是不同分辨率设备显示效果虽然可以不同,但显示的内容和样式是相同的。

我们先思考一下应该如何解决举例(1)中多分辨率适配问题导致的两款手机上同一图片显示的不一致。

很容易想到有三种思路:

思路1:使用不同的资源适配不同分辨率的设备。针对举例(1)就是再做一张640*960的图片,通过获取设备的分辨率使用相应分辨率的资源。这种方案仅适用于设备分辨率比较少的情况。如果设备分辨率很多,那么势必要针对每一种设备分辨率做一套资源,那将是游戏美工的噩梦。同时,发行时游戏资源包将变得异常大,如果采用分设备发行游戏资源包,维护和管理将变得极为困难。

思路2:使用同一资源通过资源缩放适配不同分辨率的设备。针对举例(1)就是在640*960屏幕分辨率下,将320*480的图片放大一倍后再显示。这种方案可能存在的两个问题:一是资源的分辨率比设备分辨率大,资源存在浪费;二是资源的分辨率比设备分辨率小,势必放大资源,影响显示效果。

思路3:结合方案1和方案2,使其在显示效果和资源使用率上达到平衡。

Cocos2D-x在cocos2d-2.0-x-2.0.4版本提供了多分辨率适配问题的解决方案,在这之前开发者只能自己想办法解决,而该解决方案其实就是以思路2作为依据的。

下面我们就来学习一下,Cocos2D-x是如何解决多分辨率适配问题。Cocos2D-x引入了几个全新的概念,需要理解这些概念的含义才能明白Cocos2D-x的解决方案。

·设计屏幕大小(designSize/winSize):也可以理解为逻辑屏幕大小。它是Cocos2D-x框架为开发者提供的标准界面,开发者只需要基于设定的设计屏幕大小进行开发,至于标准界面与不同设备之间的适配,则由Cocos2D-x框架实现。通过标准界面就达到了隐藏不同设备的差异,使游戏开发所有资源的映射都基于标准界面。

·实际屏幕大小(screenSize):它表示物理屏幕大小。实际上就是指不同设备的分辨率大小。Cocos2D-x框架需要获取该值,实现从设计屏幕大小到实际屏幕大小的适配。

·可视屏幕大小(visibleSize):它是建立在设计屏幕大小概念基础上的,表示能够显示的区域大小。它是设计屏幕大小的子集。

有了这些概念,就可以进一步理解Cocos2D-x的解决方案的原理。它通过获取实际屏幕大小和开发者设置的设计屏幕大小,就可以求出它们之间的比例;在渲染的时候,把资源按照这个比例来缩放绘制。

在求实际屏幕大小与设计屏幕大小的比例时,可能出现宽高比不同的情况。例如设计屏幕大小为480*320(宽高比=480/320=1.5),而实际屏幕大小为1024*788(宽高比=1024/768=1.3)。这时宽高比不同,资源也就无法缩放来填满屏幕。

Cocos2D-x定义了三种模式来处理宽高比不同的情况,在实际开发中开发者可以根据需要选择不同的模式:

·kResolutionExactFit模式:完成适应模式。通过拉伸资源的方式填满屏幕;也就是以宽比和高比作为缩放比例分别进行缩放,但这会使资源产生变形。如下图((红色线框指屏幕):

[原创]cocos2d-x研习录-第三阶 多分辨率适配器

·kResolutionNoBorder模式:无边界模式。通过宽高等比缩放,但缩放比例取宽比和高比中最大的那个。这可以确保资源不变形缩放,但这会使有一部分资源超出屏幕。如下图(红色线框指屏幕):

[原创]cocos2d-x研习录-第三阶 多分辨率适配器

·kResolutionShowAll模式: 全显示模式。通过宽高等比缩放,但缩放比例取宽比和高比中最小的那个。可以确保资源不变形缩放,但这会使资源无法填满屏幕。如下图(红色线框指屏幕):

[原创]cocos2d-x研习录-第三阶 多分辨率适配器
   下面结合基本框架HelloCpp程序代码,再一起来理解Cocos2D-x多分辨率适配的使用方法。
   在HelloCpp程序代码的入口函数_tWinMain中有下面一行代码:
   eglView->setFrameSize(480,320);
   这行代码是用于设置实际屏幕大小,这是在win32环境模拟设置手机分辨率大小。如果在设备上运行,直接使用CCEGLView::sharedOpenGLView()->getFrameSize()就可以获得不同设备分辨率大小。
   现在实际屏幕大小有了,那设计屏幕大小在哪里设置昵?
   bool AppDelegate::applicationDidFinishLaunching()
   {
      ...
      CCEGLView::sharedOpenGLView()->setDesignResolutionSize(960,640, kResolutionNoBorder);//设置设计屏幕大小
      ...
   }
   这里设置的设计屏幕大小为960*640,使用的是无边界模式。
   在HelloCpp程序里面有一个退出按钮和一张分辨率为960*640的图片,我们运行一下,结果如图:
[原创]cocos2d-x研习录-第三阶 多分辨率适配器
   由于我们的实际屏幕大小为480*320,设计屏幕大小为960*640,那么宽高压缩比都为0.5,显示图片时将压缩一半进行渲染绘制。
   接着,我们把设置设计屏幕大小这行代码注释掉,相当于不使用多分辨率适配,我们运行一下,结果如图:

[原创]cocos2d-x研习录-第三阶 多分辨率适配器

不使用多分辨率适配,图片显示时将不会被压缩,由于图片的分辨率为960*640,而实际屏幕大小 为480*320,所以屏幕只能显示图片的一半。

我们再来看一看宽高比不同的情况下,多分辨率适配的三种模式的区别,如下:

条件设置1:

eglView->setFrameSize(480,150);

CCEGLView::sharedOpenGLView()->setDesignResolutionSize(960,640, kResolutionExactFit);

运行程序,结果如图:

[原创]cocos2d-x研习录-第三阶 多分辨率适配器

可以看出在宽高比不同的情况下,使用kResolutionExactFit模式后,图片被拉伸显示。

条件设置2:

eglView->setFrameSize(480,150);

CCEGLView::sharedOpenGLView()->setDesignResolutionSize(960,640, kResolutionNoBorder);

运行程序,结果如图:

[原创]cocos2d-x研习录-第三阶 多分辨率适配器

可以看出在宽高比不同的情况下,使用kResolutionNoBorder模式后,图片未变形,但图片超出了屏幕显示。

条件设置3:

eglView->setFrameSize(480,150);

CCEGLView::sharedOpenGLView()->setDesignResolutionSize(960,640, kResolutionShowAll);

运行程序,结果如图:

[原创]cocos2d-x研习录-第三阶 多分辨率适配器

可以看出在宽高比不同的情况下,使用kResolutionShowAll模式后,图片未变形,但图片未能填满屏幕,两边有黑色空隙。

现在应该理解Cocos2D-x的多分辨率适配的三种模式吧。现在我们再来看HelloCpp中的下面一段代码:

bool HelloWorld::init()

{

...

CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();//可视屏幕大小
     CCSize winSize = CCDirector::sharedDirector()->getWinSize();//设计屏幕大小
     CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin(); //可视屏幕原点

...

CCSprite* pSprite = CCSprite::create("HelloWorld.png");
     pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));//设置精灵位置为屏幕中心

...

}

在条件设置1(kResolutionExactFit模式)中,运行结果如下:

visibleSize->(960,640)

winSize->(960,640)

origin->(0,0)

在条件设置2(kResolutionNoBorder模式)中,运行结果如下:

visibleSize->(960,300)

winSize->(960,640)

origin->(0,170)

在条件设置3(kResolutionShowAll模式)中,运行结果如下:

visibleSize->(960,640)

winSize->(960,640)

origin->(0,0)

可以看出,在kResolutionNoBorder模式下,当宽高比不同时,可视屏幕大小将小于设计屏幕大小。定义可视屏幕大小的目的就是因为在kResolutionNoBorder模式下,渲染绘制资源可能会超出屏幕显示。在设置精灵对象位置时使用可视屏幕大小而不是设计屏幕大小,可以确保在任何模式下都能够正确显示。

Cocos2D-x的多分辨率适配解决方案就讲到这里。我们可以认识到,其实Cocos2D-x提供的三种可选模式都存在着不同的缺陷,我在博客上曾经看到一篇文章,作者试图基于kResolutionNoBorder模式和kResolutionShowAll模式的特点提出新的适配解决方案。至于这个新解决方案已经超出了本内容的范围,有兴趣的同学可以自己去琢磨和研究。

----------------------------------------------------------------------------------------------------------------------------------------

注:本人在本博客的原创文章采用创作共用版权协议http://creativecommons.org/licenses/by-nc-sa/2.5/cn/), 要求署名、非商业用途和保持一致。要求署名包含注明我的网名及文章来源(我的博客地址:http://www.cnblogs.com/binbingg)。