5.2 分辨率适配经验
5.2.1 宽度或高度锁定
我们希望所有的机型都能够很完美地适配,不要拉伸!不要黑边!FIXED_HEIGHT或FIXED_WIDTH模式是比较容易做到的。
要做到上面的要求,需要选取一个范围,即要适配的分辨率比例的范围。我们都知道iPhone 5的比例非常长,应该没有什么机器比这个比例更长的了,所以一般笔者将iPhone 5的比例设置为要适配的极限比例,也就是说,如果有比iPhone 5更长的手机,笔者就基本放弃这个机型了。接下来选择一个最扁的比例,一般在平板电脑上的比例会更扁一些,纵观主流的分辨率,基本都在iPhone 5和iPad之间,所以笔者习惯将要适配的比例在iPhone 5到iPad之间(这里的是以横屏游戏为例,如果是竖屏游戏,只需要把宽和高对调一下即可)。也就是说,假设选择固定高度的FIXED_HEIGHT模式,那么就要选择一个最宽和最窄的宽度。
选择好比例之后,需要好好设计一下游戏内容,以方便不同分辨率的适配,主要包含游戏的背景、游戏的内容区域,以及UI等。
背景的设计是非常重要的一步,因为背景设计的好坏,直接决定了是否有黑边,以及游戏内容的布局。首先,背景图需要有多大?其次,游戏区域只能有多大?这些问题需要根据游戏的内容来设计。
如果是一个横屏的斗地主游戏,可以将游戏区域放在游戏的正中间,游戏内容可以根据游戏区域的原点为相对坐标计算,这时候两边各有一部分区域是可裁剪的。
如果是一个竖屏的雷电射击游戏,可以将游戏区域放在正下方,上方是可裁剪区域,敌人从上方出现,可以将上方的可裁剪区域也纳入游戏区域,敌机根据左上角为原点设置相对坐标。
如果是一个消除类游戏,如果是横屏的,一般把游戏区域放在正中间,左右两边裁剪;如果是竖屏的,一般也把游戏区域放在正中间,上下两边是可裁剪区域。
5.2.2 计算设计分辨率
使用FIXED_HEIGHT或FIXED_WIDTH模式结合一个比较大的背景,一般可以解决大部分游戏的分辨率适配问题,但如果游戏背景并不是锁定宽度或高度的,那么就需要选择其他的分辨率适配策略了。
下面介绍一个简单的适配示例,如图5-6所示。首先背景尺寸是1280×800,这个分辨率没有任何讲究,是美工随便给出的一个分辨率,是一个足够大的尺寸,宽度和高度都不进行锁定,而是根据实际设备的分辨率进行动态调整,这个分辨率尽管不怎么标准,但还是可以用来完成完美适配。
图5-6 分辨率480×320
游戏中有两部分UI,主界面的菜单面板是居中对齐,getWinSize得到的大小的一半即是居中的位置,面板设置锚点为(0.5,0.5),并设置居中的位置即可。第二部分UI是顶部的信息栏,信息栏的位置是靠上居中,信息栏设置锚点为(0.5,1.0),然后设置getWinSize的width×0.5f为x坐标,height为y坐标即可。
在这里选择的策略是SHOW_ALL,但是设计分辨率需要动态计算出来(一般的代码这里都会设置一个分辨率),因为要使用好1280×800的背景图,关键有以下几点:
❑ 不拉伸,不留黑边。
❑ 根据手机的分辨率调整可视区域(设置的标准分辨率)。
❑ 当目标分辨率比背景还要宽时,把目标分辨率等比缩小,直到分辨率内容全部在可视区域内。
❑ 当目标分辨率比背景还要高时,把目标分辨率等比缩小,直到分辨率内容全部在可视区域内。
❑ 当目标分辨率比背景小时,把目标分辨率等比放大,直到分辨率内容全部在可视区域内。
我们的背景分辨率是1280×800,720是笔者自己定义的一个值,因为笔者不希望整个背景太宽,所以进行了限制,然后根据实际的分辨率与预期分辨率计算出期望的高和宽(要么高变,要么宽变),代码如下。
float height = 800.0f; float width = 1280.0f; float ratio = sz.width / sz.height; float maxratio = width / height; float minratio = width / 720.0f; if (ratio > maxratio) { //比最宽的还要宽 height = width / ratio; } else if(ratio < minratio) { //比最窄的还要窄 width = height * ratio; } pEGLView->setDesignResolutionSize(width, height, SHOW_ALL);
上面代码的适配效果如下:我们在PC上可以设置窗口的大小(也就是FrameSize),以此来调试程序在对应分辨率下的适配情况,可以先看一看效果。这里笔者选择了两个不同的分辨率进行展示,一个是480×320,如图5-6所示,另一个是550×320,如图5-7所示,可以看到在两个差异比较大的分辨率下都有不错的适配效果。
图5-7 分辨率550×320
动态调整设计分辨率结合SHOW_ALL策略可以实现一般策略实现不了的适配规则,例如,希望在不同的分辨率下能够根据设备的分辨率来进一步调整窗口中呈现的内容,不锁定宽度和高度,也不拉伸或留黑边。此外,上面的例子同时也演示了简单的坐标编码。
5.2.3 场景固定内容
有时在进行分辨率适配时,还要考虑游戏场景中的固定内容,固定内容指无论如何都需要等比缩放的部分,如果这部分内容的比例发生了变化,将会造成糟糕的游戏体验。
例如,下面这个在指定区域内进行的物理小游戏,每一个关卡都摆放了各种障碍物和目标,我们需要发射出子弹在障碍物和上下左右四个方向的墙壁上弹射,来命中目标,障碍和目标的摆放都是游戏策划精心设计的,确保每一个关卡都可以命中所有的目标。如果由于分辨率的改变而使得四个方向的墙壁位置发生了变化,就会导致玩家不一定能命中所有的目标。如图5-8演示了在1024×768分辨率下的游戏运行界面。
图5-8 分辨率1024×768
该游戏的固定内容是一块960×640的区域,但上下左右都有额外的显示内容进行填充(使用了SHOW_ALL模式结合动态计算设计分辨率),当分辨率变化时,战斗区域会居中显示,并且左右两边出现额外的墙壁,如图5-9所示。要实现这样的功能,可以将战斗区域左下角的x坐标设置为(WinSize.width _ 960) / 2, y坐标设置为(WinSize.height_640)/2,然后战斗区域内的对象都以此坐标进行相对位置的设置。
图5-9 分辨率1136×640
我们还可以逆向思考,使用更简单的方法,战斗区域始终以(0,0)点为原点,也就是不需要考虑相对位置的编码,通过将战斗区域挂载到一个节点上,然后移动该节点,将整个战斗区域挪到屏幕的正中间,这样实现起来会更加方便。
5.2.4 经验小结
在这里总结一下分辨率适配的几点经验:
❑ 对于4种适配策略、设计分辨率、各种窗口尺寸的含义基础概念一定要掌握扎实。
❑ 通过调整设计分辨率可以实现更加复杂的适配策略。
❑ 在PC上使用setFrameSize可以调试当前适配规则在各种分辨率下的效果。
❑ 通过将固定内容挂载到节点上,再移动该节点,可以简化固定内容内部的坐标编码。