3.4 Cocos2d-x中屏幕适配的原理
在之前所实现的游戏开始界面中,用到了精灵类来显示游戏背景。由于在本书的范例中大多数将默认屏幕尺寸设置为了640*360,因此不需要去为适配的问题而过多担心。但是在实际的游戏开发中这样理想的环境几乎是不会存在的,因此就需要了解怎样在Cocos2d-x中对不同尺寸的屏幕进行适配。
在移动开发中由于移动设备的碎片化,导致了开发者根本无法得知用户会使用何种尺寸的设备。虽然说设备所使用的屏幕尺寸只是固定的十几种,但是由于在游戏中大量使用图片素材,如果真的为每一种尺寸都配上相应的素材,那么无疑最终生成的游戏文件将是非常巨大的。因此就需要找到一套能够适配大多数设备的屏幕适配方案。
实际上在Cocos2d-x中已经提供了一套相对完整的解决方案,能够适应移动开发中的各种分辨率大小,以及不同宽高比所带来的碎片化问题。因此在使用Cocos2d-x时,只要遵循一定的方法就能够解决不同设备下屏幕适配的难题。
首先,我们先来了解一下在游戏开发中设备的分辨率和宽高比分别是怎样影响到游戏的兼容性的。
(1)屏幕大小:从最初的320*240到目前比较普及的1920*1080再到一些所谓的4K分辨率,从三寸出头的手机到10寸的iPad,这么多种不同尺寸的屏幕不可能做到用一套素材就能够完全满足。试想在上一节素材中使用的背景图片如果用640*360的分辨率,那么在一些小屏幕的设备中显然能够很好地使用,而如果放在iPad(10.3英寸)中运行那就像是漫山遍野的马赛克,叫人忍无可忍。而如果在小屏幕的设备中使用高分辨率的图片素材呢,则会造成一些设备的性能瓶颈。所以要根据分辨率的不同而选择不同的素材是很必要的。
(2)宽高比:宽高比简单地说就是设备的屏幕是长的还是方的,比如说常见的16:9或者是4:3的屏幕,它们的形状显然是不同的。在游戏开发中由屏幕分辨率所带来的问题是比较容易解决的,一般准备3套不同质量的素材就能够很好地解决。但是由宽高比所带来的问题就需要通过Cocos2d-x所提供的方案来解决了。
根据计算可以知道在横屏状态下,显然16:9的屏幕要比4:3的屏幕宽不少,因此在4:3的屏幕上完整显示的图片在16:9的屏幕上显示就会出现如图3-9所示的几种可能。
图3-9中使用了4部iPhone手机的机身作为模板,其中左上角的那一部的宽高比为4:3,而其他几部的屏幕宽高比均为16:9,用正方形的网格来代替手机中显示的图案。可以看到在左上角的手机中网格是正常显示的,而在右上角的手机中虽然显示了全部的内容,但是通过屏幕中的网格可以看出图像是发生了变形的,这在一些风景类的背景中也许看不出来,但是游戏人物却会给用户一种很奇怪的感觉。而图中左下角的手机屏幕中则是保证完整地显示屏幕内容而牺牲了一部分宽度,可以看到其屏幕上显示的内容与左上角手机屏幕中显示的内容长宽比是完全相同的,但是在左右两侧留下了一些空白。而图中右下角手机显示使用的方案则与之相反,它是保证了最大限度地利用手机屏幕,但是为了保证原有的长宽比,有一部分内容是超出了屏幕内容无法显示出来的。
图3-9 将宽高比为4:3的图片在16:9的屏幕上显示的结果
在Cocos2d-x中也提供了几种与图3-9中展示的类似的适配方法,分别是:EXACT_FIT、SHOW_ALL、FIXED_HEIGHT、FIXED_WIDTH和NO_BORDER。下面将依次介绍这5种方案。
1.EXACT_FIT
EXACT_FIT所使用的方法就类似于图3-9右上角所展示的方案,通过对画面进行拉伸来保证游戏中的角色、按钮等都固定在正常显示状态下该在的位置,无论屏幕尺寸是720*480还是1280*720或者是852*480等任意尺寸比例,元素总能显示在固定的位置。它的优势就是通过拉伸来使画面完整地呈现在屏幕上,因此可以使用具体的数值来安排屏幕内容的摆放,不会因为屏幕的尺寸而使内部元素位置出现错乱。
然而,拉伸虽然保证了在任何情况下屏幕都能过被百分之百利用且坐标系不会混乱,但是总会造成一些不好的结果。比如说由于图片拉伸而造成的变形,会使本来该是圆形的精灵变成了椭圆的;本来正方形的按钮变成了长方形,严重影响到游戏的可玩性,因此并不推荐此种方法。
2.SHOW_ALL
还有一种方案叫做SHOW_ALL,就比较类似于图3-9左下角展示的方案,通过牺牲一部分屏幕面积来达到两个目的:解决了游戏画面根据屏幕尺寸自动放大缩小的问题;保证了显示区域的宽高比,使得游戏更容易设计,如图3-10所示。
图3-10 使用方案SHOW_ALL在不同宽高比下的两种可能
3.NO_BORDER
NO_BORDER则采用了一种相反的思想,是在保证宽高比的前提下牺牲一部分可视面积来达到最大利用屏幕可视区域的目的,如图3-9右下角的方案就采用了这一思想。由于在开发时所使用的坐标是以图像所在的坐标系为基础的,而采用NO_BORDER方案则使图像一部分不能显示在屏幕上,这其中也包括了坐标系的原点因此会导致坐标系的混乱。为了解决这一问题就需要引入VisibleSize和VisibleOrigin的概念。
如图3-11就展示了在不同宽高比下使用NO_BORDER方案后图像在屏幕上显示的情况,以左侧为例,此时若要使图像宽度与屏幕宽度相同,则紫色区域(矩形AHIB和矩形KDJ所示的区域)超出了屏幕范围不被显示了。而此时坐标系的原点D也是在屏幕外的,因此当需要计算坐标,如屏幕中某个按钮的位置时就会很不方便。因此就采用K点作为VisibleOrigin。
图3-11 使用方案NO_BORDER需要引入VisibleSize和VisibleOrigin用于计算坐标
而VisibleSize则是可以配合VisibleOrigin使用、可以用来获取当前屏幕的高度和宽度,在Cocos2d-x中使用它们的方法如下:
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize(); CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
提示:由于在开发时,Windows窗口下也可以直接运行程序,并且能够按照设置的窗口尺寸进行试验,因此在PC环境下很难体现出适配方法所带来的区别。但是在移动设备上,Cocos2d-x将会使编译完成的程序自动缩放至一个与屏幕相适应的尺寸而保持与设置的窗口相同的宽高比,此时这些适配方案的作用才能够体现出来。
4.FIXED_HEIGHT和FIXED_WIDTH
最后再来介绍一下FIXED_HEIGHT和FIXED_WIDTH,这两种方案比较近似,所以我们放在一起说。简单地来说,不管是NO_BORDER还是SHOW_ALL都会根据屏幕的宽高比进行适当的缩放,但是在不同的宽高比下,可能屏幕宽度与画面宽度相同而高度不同,也可能是屏幕高度与画面高度相同而宽度不同。但是FIXED_HEIGHT则是无论怎样的宽高比都仅保证屏幕的高度与画面高度相同。一般会出现在一些类似于超级马里奥这样的横版游戏中。因为在这类游戏中游戏地图一定是超过了屏幕宽度的,因此超出屏幕的多少对实际游戏效果影响不大。与之类似的是在一些像打飞机这样的纵版射击游戏中则会选用FIXED_WIDTH。
那么在什么地方选择使用哪一种方案呢?在文件AppDelegate.cpp中对applicationDidFinishLaunching方法的重写中会有一句代码:
director->getOpenGLView()->setDesignResolutionSize(640, 480, ResolutionPolicy::SHOW_ALL);
可以将其中的SHOW_ALL替换为其他方案。
在游戏画面实际上同时超出了屏幕的宽度和高度的情况下(比如某些RPG游戏中),地图的宽高都超出了屏幕,此时可选用NO_BORDER或SHOW_ALL方案。