木匣子

Web/Game/Programming/Life etc.

简单的 cocos2d-x 屏幕适配策略

开发手机游戏时常常需要对不同的设备进行分辨率适配。在 PC 游戏开发中,一种比较直截了当的作法——全屏显示游戏,将屏幕锁定在一个预设好的分辨率中即可。但这在当下的移动设备中无法做到。由于生产标准不一,市场上有各种让人零乱的 Android 设备尺寸,即便是规格较统一的 iOS 设备,如今也正走向多分辨率分裂的格局:

  • iPhone4S 960×640
  • iPhone5/5S 1136×768
  • iPad 1024×768
  • iPad retina 2048×1536
  • and so forth…

为了应对不同的屏幕,Cocos2d-x 游戏引擎提供了一组分辨率适配策略:

  • Show All
  • No Border
  • Exact Fit
  • Fixed Width
  • Fixed Height

详细的使用方法可参见此官方文档。这些策略通过一些妥协使得游戏在不同的设备上得以较完整的显示。文档中提到一个重要概念叫“设计分辨率”(Design Resolution),表示设计组在这个尺寸下进行游戏素材的设计。在这里对于这些显示策略的优势与不足作一些简单的介绍:

Show All

将游戏画面完全显示在屏幕上,若宽高比大于设计分辨率,屏幕左右将出现黑边;若宽高比小于设计分辨率,屏幕上下将出现黑边——这有点像在4:3屏幕上看16:9的宽屏电影。该策略较为常用,适用于大部分 2D 游戏。

No Border

一些游戏为了更好地利用屏幕,则为使用 no border 方式,该策略在保证设计分辨率的宽高比的情况下,将画面放大到完全填充屏幕。使得在设备宽高比不同于设计分辨率时,游戏部分内容无法呈现在屏幕内。通常适用于 3D 类游戏,主要内容位于屏幕中间部分,对于边界的损失可以无视。

Exact Fit

通过拉伸画面的方式,将游戏画面完全适应屏幕分辨率。这种做法在不同的屏幕上可能导致画面变形。很少有游戏会使用。

Fixed Width

仅保证游戏画面水平场景完整显示于屏幕中,而竖直场景(高度)可能小于屏幕高(上下出现黑边),或超出屏幕(游戏画面溢出)。适用于横版闯关游戏。

Fixed Height

类似于 fixed width,仅保证游戏的垂直场景。适用于竖版闯关/飞行游戏。


综上所述,对于 2D 游戏来说,show all 可能是当下较多游戏的选择。但是有没有更好的利用屏幕的方式呢,倘若能在 show all 的基础上加以改进,完全消除黑边,岂不是更好。于是我想到了一种简单的方法,动态计算“设计分辨率”,在保证较小调整的基础上,消除屏幕黑边:

计算缩放系数 k 使用得设计分辨率能完整显示在设备屏幕中,然后计算x或y,补足黑边占用的屏幕尺寸。

// define the design resolution
var designWidth = 960;
var designHeight = 640;

// retrieve device resolution
var deviceWidth = cc.visibleRect.width;
var deviceHeight = cc.visibleRect.height;

var k = 1, x = 0, y = 0;

k = deviceWidth / designWidth;
var scaledHeight = designHeight * k;
if (scaledHeight <= deviceHeight) {
    y = (deviceHeight - scaledHeight);
} else {
    k = deviceHeight / designHeight;
    var scaledWidth = designWidth * k;
    if (scaledWidth <= deviceWidth) {
        x = (deviceWidth - scaledWidth);
    } else {
        throw new Error("can't fit the screen!");
    }
}

// print out parameters
cc.log("device width:" + deviceWidth);
cc.log("device height:" + deviceHeight);
cc.log("k:" + k + " x:" + x + " y:" + y);

// resize the design resolution
cc.view.setDesignResolutionSize(
        960 + x / k, 640 + y / k,
    cc.ResolutionPolicy.SHOW_ALL);

// after screen fitted
cc.log("view width:" + cc.visibleRect.width + " view height:" + cc.visibleRect.height);

若设计分辨率为 960×640 在以下不同设备上运行,调整后的设计分辨率如下:

  • iPhone4S 960×640
  • iPhone5/5S 1136×640
  • iPad/iPad retina 960×720
  • Samsung I9100 1136×640

这些尺寸能完全容纳设计分辨率,并且消除了黑边。

但是设计分辨在宽或高的其中一个维度变化了,游戏的内容又要如何呈现?一个简单的作法是在原来黑边的位置使用一些装饰性的界面元素进行修饰;如果游戏使用了 Cocos Studio 进行 UI 开发,则可以通过开启根节点的“自适应分辨率”来进行屏幕适配——这是一个绝佳的方案。

以上代码在 Cocos2d-js 3.0 RC2 测试通过。 其它版本可能需要在 setDesignResolutionSize 后对 cc.visibleRect 进行重置。
cc.view.adjustViewPort(true);
cc.view.setDesignResolutionSize(...);
cc.view.resizeWithBrowserSize(true);