cocos2d-x 多分辨率支持

时间:2023-02-08 23:15:37

转自:http://blog.csdn.net/xujiezhige/article/details/8673513

http://article.ityran.com/archives/3762

 

最近遇到多分辨率支持问题,所以查了一些资料。将一些收获共享一下,以便自己和其他需要的朋友日后参考。

如果我要建立一个cocos2d-x项目,我的目标是支持iphone3G( 480, 320 ),iphone4/4s( 960, 640 ), iphone5( 1136, 640 ),ipad1/2( 1024, 768 ),ipad 3( 2048, 1536 ),以及所有android设备(其分辨率可能是( 800, 480 )等其它各种分辨率)?我该如何规划呢?但在你规划之前是否清楚cocos2d-x是如何为多分辨率支持进行设计的?

所以首先来看一下,cocos2d-x提供的基本支持。

  1. Cocos2d-x自从2.0.2版本起,不在采用-hd,-ipd,-ipdhd等文件名称后缀了,因为其目标是支持是跨平台,不再是单单IOS系统了。改用CCFileUti类中的setResourceDirectory()(2.0.4版本)或者setSearchPaths()(2.1.1版本)。我们只需在resource目录下为每个系统建立自己的目录,并将对应资源放进去(具体参考http://www.cocos2d-x.org/projects/cocos2d-x/wiki/Mechanism_of_loading_resources)。

  2. Cocos2d-x自从2.0.4版本起,去除了setRetinaEnable()函数,因为cocos2d-x将默认开启retina(如果设备支持的话),并带来了全新的概念。你需要理解designSize和contentScaleFactor,以及designSize将如何映射到窗口上。我简单解释一下:

    1.designSize:从字面意思就是设计大小。“设计”两字为何意?好比我们抛开不同设备分辨率,就假定只有一个标准界面,让标准界面隐藏背后不同设备的差异。这个标准界面就是designSize。Cocos2d-x也将向标准界面“看齐”, 一旦我们设置了designSize,cocos2d-x中的getWinSize就成了我们的designSize。我们一般设置其为(480,320)“经典”大小,但假如你的初始资源是(1024,768)大小的,那么我们可以使用(512,384)的设计界面,保证资源的宽高比和设计宽高比相同,能保证资源全屏。

    2.contentScaleFactor:从字面意思内容缩放因子,内容即我们的资源(我是这么理解的)。一般contentScaleFactor = resourceHeight / designSize.Height;为什么要有这个东西?因为刚才我们说了designSize,我们将其设置为(480,320),而且以后我们的winSize就成了designSize,但是我们用在iphone4中背景图片还是(960,640)的,此时我们的图片是屏幕4倍大,就显示不开了。有了缩放因子,我们就能将背景图片(960,640)的编程(480,320)。这样原本全屏的资源,现在仍然是全屏的。

    3.designSize如何映射到“真实窗口”上的:这个过程就是将我们的”标准界面“映射到真实的设备上。我们真实设备的大小可能有很多变化。(480,320)的设计界面如何映射到,假如说(1136,640)的呢?有三种kResourceExactFit,kResourceNoBorder,kResourceShowAll。

    第一种是完全适应,即不论你真是设备分辨率多么”怪异“,它都将设计界面恰好的贴上去。看似”完美“的方案,但也存在瑕疵,那就是变形。你的人物可能”变
    胖“,或者”拉瘦“。

    第二种是没边界,即没有边界限制,假如你的”设计界面“是(480,320),目标设备是(1136,640)。如果目标设备的长宽比率和设计界面的长宽比率不一
    样,那么这个模式采用超出目标设备边界的拉伸方式,也就是设计界面有一边完全适应,另一边超出的方式。在我们当前假设的这种情况,那就是会将设计界
    面的宽拉伸到1136.然后高等比放大。这样的话,我们会发现,宽正好”全屏“,但是高超出去。这也就是所谓了没有边界限制的”好处“。

    第三种是全显示,即全部显示,假如你的”设计界面“是(480,320),目标设备是(1136,640)。那么这种模式会保证你的设计界面一定能全部显示。也就
    是说,如果目标设备的长宽比率和设计界面的长宽比率不一样,那么这个模式采用限制到目标设备边界的拉伸方式。在我们当前假设的这种情况,那就是会将
    设计界面的高拉伸到640.然后宽等比放大。这样的话,我们会发现,高正好”全屏“,但是宽被”挤“了(在两边留有黑边)。这也就是所谓了全部显示的”好处“。

    (具体参考http://www.cocos2d-x.org/projects/cocos2d-x/wiki/Multi_resolution_support

  3. 另外cocos2d-x有个“诡异”的特点(至少在cocos2d-x 2.1.1版本),那就是当你开启【iphone Retina 4-inch】的时候,如果你没有设置启动封面,那么winSize仍将是(960,640)。所以必须设置启动封面,才能得到winSize(1136,640)。

知道cocos2d-x对过分辨率的支持后,我们就更加能理解好自己项目要怎样才能支持多分辨率。如果你用到CocosBuilder(如果你还不会使用,就请参考本人的【CocosBuilder教程系列】),那么如何让CocosBuilder也支持多分辨率呢?

  1. 因为CocosBuilder的文件读取库(即CCBReader读取ccbi文件),也是使用CCTexture来加载的,所以我们前面讲到的目录搜索规则也会自动被使用到ccbi的文件加载中去。虽然CocosBuilder有跟Cocos2d一样的的承诺“-hd,-ipd,-ipdhd",但这些在cocos2d-x作用已经失效。

  2. 由于我们面向多分辨率,所以我们一定在CocosBuilder中使用百分比模式来设置坐标和大小。否则,你设定的坐标就不会自动适应对应的设备分辨率。例如:你设置一个登陆框,你不应该将其坐标设置为(512,384),因为这个坐标在(480,320)的iphone3G或者android设备,可能直接看不到,而且和其他元素之间的相对距离也就混乱不堪。所以使用百分比(50%,50%),能保证在任何设备上都是居中的。
通过上面讲述,你应该能找到自己的多分辨率支持解决方案。一套资源也好,两套,三套都可以,主要还是看每个游戏自己的需求。 ###################################################################### 

这篇涉及到的API只适用于cocos2d-x 2.0.4

android的分辨率由于太多了很难来适配。但是Cocos2d-x提供了CCEGLView::setDesignResolutionSize() 和 CCDirector::setContentScaleFactor()来帮助你使用最小的工作量来让你的的游戏运行在不同分辨率下。

基本原则

自从2.0.4版本之后我们已经把所有和enableRetina方法相关的代码移除了。因此从cocos2d-2.0-x-2.0.4开启高清模式就消失了。在ios平台上,假如设备支持retian显示,我们是默认支持的。

你可以通过CCEGLView::sharedOpenGLView()->getFrameSize()方法来得到屏幕的真实分辨率大小。例如以上那个函数在Iphone4S的横屏状态下返回“960*640”。

但是怎么样使用非retina坐标和retina设备相关起来?这有两个概念你不得不知道。一个是designResolutionSize,一个是contentScaleFactor。

designResolutionSize

所有你游戏的坐标都依赖设计分辨率,不用去关心设备屏幕大小。假如你游戏的UI布局在所有的分辨率下都是相同的,那么你只需要设置这个坐标就可以了。设计分辨率是通过CCEGLView::sharedOpenGLView()->setDesignResolutionSize(width, height, policy)方法来设置的,第一,二个参数分别是设计分辨率的宽度和高度,第三个参数是你想要的模式。后面将会解释第三个变量。

你也可以使用好几套资源在不同设备上,这样你可以有更好的显示效果。你可以调用CCFileUtils::sharedFileUtils()->setResourceDirectory(path_string)这个方法来设置资源所在的文件夹,与此相应的你就需要设置contentScaleFactor。

下面就是HelloCpp项目里的代码片段。

   
   
  1. typedef struct tagResource
  2. {
  3. cocos2d::CCSize size;
  4. char directory[100];
  5. }Resource;
  6. static Resource smallResource = { cocos2d::CCSizeMake(480, 320), "iphone" };
  7. static Resource mediumResource = { cocos2d::CCSizeMake(1024, 768), "ipad" };
  8. static Resource largeResource = { cocos2d::CCSizeMake(2048, 1536), "ipadhd" };
  9. static cocos2d::CCSize designResolutionSize = cocos2d::CCSizeMake(480, 320);
   
   
  1. bool AppDelegate::applicationDidFinishLaunching() {
  2. // initialize director
  3. CCDirector* pDirector = CCDirector::sharedDirector();
  4. CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();
  5. pDirector->setOpenGLView(pEGLView);
  6. // Set the design resolution
  7. pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionNoBorder);
  8. CCSize frameSize = pEGLView->getFrameSize();
  9. // In this demo, we select resource according to the frame's height.
  10. // If the resource size is different from design resolution size, you need to set contentScaleFactor.
  11. // We use the ratio of resource's height to the height of design resolution,
  12. // this can make sure that the resource's height could fit for the height of design resolution.
  13. // if the frame's height is larger than the height of medium resource size, select large resource.
  14. if (frameSize.height > mediumResource.size.height)
  15. {
  16. CCFileUtils::sharedFileUtils()->setResourceDirectory(largeResource.directory);
  17. pDirector->setContentScaleFactor(largeResource.size.height/designResolutionSize.height);
  18. }
  19. // if the frame's height is larger than the height of small resource size, select medium resource.
  20. else if (frameSize.height > smallResource.size.height)
  21. {
  22. CCFileUtils::sharedFileUtils()->setResourceDirectory(mediumResource.directory);
  23. pDirector->setContentScaleFactor(mediumResource.size.height/designResolutionSize.height);
  24. }
  25. // if the frame's height is smaller than the height of medium resource size, select small resource.
  26. else
  27. {
  28. CCFileUtils::sharedFileUtils()->setResourceDirectory(smallResource.directory);
  29. pDirector->setContentScaleFactor(smallResource.size.height/designResolutionSize.height);
  30. }
  31. ...................
  32. ...................
  33. }

contentScaleFactor

ContentScaleFactor是指ResourcesSize 和 designResolutionSize的比例系数。一般的,你可以通过’ResourceBackGround.height/DesignResolution.height’ 或 ‘ResourceBackGround.width/DesignResolution.width’的做法来设置。选择怎么样的方式是依靠你游戏的设计。
下面就用插图的方式来说明一下,我们这里使用的高度来计算这个比例值。

cocos2d-x 多分辨率支持

图表1:资源大小=960*640,设计分辨率大小=480*320,目标设备屏幕大小=800*480,RH/DH=RW/DW=2.0f,第三个参数选择的是NoBorder模式。

当使用NoBorder模式的时候,有一些背景区域显示到屏幕以外去了。假如你使用绝对坐标在设计分辨率大小(480*320),你游戏的一些UI可能会显示不全。为了解决这个问题,你不得不设置这个坐标依据’visible rectangle’(可见矩形)的。你可以得到可见矩形的起点,通过CCDirector::sharedDirector()->getVisibleOrign()方法。调用CCDirector::sharedDirector()->getVisibleSize()方法你就可以确定屏幕上面的9个点, 左边,右边,上面,下面,中间,左上角,右上角,左下角,右下角。

假如你的游戏的所有坐标就是依靠这9个点,那么你的游戏就可以全屏展示了。

关于怎么计算这些点,你可以参考TestCpp项目里面的“VisibleRect”类。

cocos2d-x 多分辨率支持

图表2:资源大小=1024*768,设计分辨率大小=480*320,目标设备屏幕大小=800*480,RH/DH!=RW/DW=,第三个参数选择的是NoBorder模式。

当RH/DH不等于RW/RH的时候,你就需要选择的是相对于设计分辨率的宽度比例还是高度比例。

在图表2中,我们仍然使用高度比例来计算contentScaleFator,因此资源背景的高度将会适应设计分辨率

在将设计分辨率绘制到屏幕上之后,标记① –> 标记②, 和标记③将会在屏幕外面。

现在,你有两个选择来让你的游戏全部显示出来。一种是让你的背景图变宽点。另外一种是去设置contentScaleFactor为宽度的比例。

模式

现在cocos2d-x支持三种模式

Exact fit

整个应用程序的内容都会在特殊区域可见,并且不用提供这些比例系数。可能会出现形变,所有的应用程序看起来可能会是拉伸或者压缩的。

No border

当设置了屏幕高宽比之后,整个应用程序将会显示在这个特殊区域,但是没有形变,但是可能一些裁剪。

Show all

当设置了屏幕高宽比之后,整个应用程序也是会显示在这个特殊的区域内,没有形变,不过可能会出现两条黑边。

cocos2d-x 多分辨率支持

图表3:资源大小 = 1024*768;设计分辨率大小 = 480*320;目标设备屏幕大小 = 800*480;RH/DH != RW/DW; ShowAll Policy

标记② 和标记③都是黑色的矩形区域。但是他们不同的,标记③是在Opengl可视区域外面的,因此你不能把任何的游戏元素放在上面。标记②的出现是因为RW/RH不等于DW/DH,但是在Opengl可视区域,你可以放置你的游戏元素在那里。

假如开发者为了更好的游戏显示使用NoBorder模式,那么你需要使用相对坐标。