quick-cocos2d-x 多分辨率适配详解

多种分辨率的适配一直都是一个蛋疼的问题,各家公司可能都有自己的一套方案。今天我为大家介绍的是我们在多款游戏里实践后的解决方案,相对来说成本和实现难度都较低,效果也很不错。

多种分辨率适配的原理

因为横屏和竖屏的原理完全相同,所以本文先以竖屏为例,后文再说明横屏的处理。

制作一张 640×960 像素的图片,并传入设备查看:

  1. 查看时将图片缩放到合适大小,确保图片左右两边正好填满整个屏幕
  2. 在不同分辨率的设备上,这张图片的显示效果差异体现在图片上下是否能够填满屏幕。

例如在 480×800 的设备上,这张 640×960 图片会被缩小为 480×720 像素来显示,左右填满屏幕,上下出现黑边。

在一些常见分辨率中,图片的显示效果:

缩放比例 = 屏幕像素宽度 / 图片像素宽度
  • 屏幕尺寸 _640x960 像素,缩放比例 100%,正好填满整个屏幕
  • 屏幕尺寸 640×1136 像素,缩放比例 100%,上下有黑边
  • 屏幕尺寸 _480x800 像素,缩放比例 _75%,图片缩放后尺寸 _480x720 像素,上下有黑边
  • 屏幕尺寸 _480x854 像素,缩放比例 _75%,图片缩放后尺寸 _480x720 像素,上下有黑边
  • 屏幕尺寸 768×1024 像素,缩放比例 120%,图片缩放后尺寸 768×1152 像素,无黑边,但图像上下有裁剪(超出屏幕无法显示)

上下有黑边是肯定不好看的。那要保证填满屏幕,我们只需要将图片做得更大一点就可以了。图片高度的计算:

图片高度 = 屏幕像素高度 / (屏幕像素宽度 / 图片像素宽度)

按照这个公式,上述分辨率,图片的高度应该是:

  • 屏幕尺寸 _640x960 像素,图像高度 960 像素
  • 屏幕尺寸 640×1136 像素,图像高度 1136 像素
  • 屏幕尺寸 _480x800 像素,图像高度 1066.67 像素
  • 屏幕尺寸 _480x854 像素,图像高度 1138.67 像素
  • 屏幕尺寸 768×1024 像素,图像高度 853.3 像素

其中最大值是 1138.67,考虑制作方便,高度取值 1140。也就是说 640×1140 的图片可以完全填满上述各种分辨率的屏幕。

在游戏里我们也可以借鉴这种方式。不管屏幕多大,反正我把游戏场景的宽度都给定死,就是 640。那么在不同设备上,要处理的问题就是场景高度的变化。以此为基础,适配多种分辨率的原理就很简单了:

  1. 游戏场景的宽度固定。
  2. 根据屏幕分辨率计算出游戏场景的高度。
  3. 使用较大的背景图,确保任何分辨率下都可以填满屏幕。
  4. 根据场景高度来定位显示内容。

虚拟分辨率

为了和设备屏幕分辨率区别开,我将游戏里使用的分辨率称为“虚拟分辨率”

在“虚拟分辨率”中,坐标系的尺寸是“点”。后文称为“Point,缩写为 pt”。

根据前面计算图片高度的公式,在不同设备上,虚拟分辨率的宽度是固定的,而高度则不同。在 quick-cocos2d-x 里要实现这个虚拟分辨率的自动计算,只需要使用“FIXED_WIDTH”屏幕缩放策略。

打开 config.lua 文件,指定以下代码即可:

CONFIG_SCREEN_WIDTH     = 640
CONFIG_SCREEN_HEIGHT    = 960
CONFIG_SCREEN_AUTOSCALE = "FIXED_WIDTH"
  1. CONFIG_SCREEN_WIDTH 和 CONFIG_SCREEN_HEIGHT 定义了一个“虚拟分辨率”的参考值。
  2. 游戏引擎根据参考值和 CONFIG_SCREEN_AUTOSCALE 设置,最终计算出在设备上使用的“虚拟分辨率”。

我们在 quick-cocos2d-x 启动时可以看到如下信息:

# CONFIG_SCREEN_AUTOSCALE      = FIXED_WIDTH
# CONFIG_SCREEN_WIDTH          = 640.00
# CONFIG_SCREEN_HEIGHT         = 1066.67

此处的 CONFIG_SCREEN_HEIGHT 就由引擎做了调整,不再是 config.lua 里指定的参考值。最终,CONFIG_SCREEN_WIDTH 和 CONFIG_SCREEN_HEIGHT 就是游戏场景的虚拟分辨率尺寸。

内容的定位

quick-cocos2d-x 在引擎初始化的时候就算好了一些特定的坐标值,我们在游戏里可以用这些坐标值当做“参考点”来定位我们的内容。

# display.width                = 640.00
# display.height               = 1066.67
# display.cx                   = 320.00
# display.cy                   = 533.33
# display.left                 = 0.00
# display.right                = 640.00
# display.top                  = 1066.67
# display.bottom               = 0.00
  • display.widthdisplay.height 是虚拟分辨率的尺寸
  • display.cxdisplay.cy 是屏幕中心的坐标
  • display.leftdisplay.rightdisplay.topdisplay.bottom 是屏幕四个角的坐标

有了这些“参考点”,定位内容就很简单了。

例如要在屏幕右上角放置一个按钮图片,用以下代码即可:

local x = display.right - 100 -- 图片中心在屏幕右边往左 100pt
local y = display.top   - 100 -- 图片中心在屏幕顶部往下 100pt
local sprite = display.newSprite("Button.png") -- 创建 sprite 对象用于显示图片
sprite:setPosition(x, y) -- 设置这个 sprite 对象的坐标

要在屏幕上显示一张背景图,确保图片中心和屏幕中心重叠:

local bg = display.newSprite("Background.png")
bg:setPosition(display.cx, display.cy)

所以只要合理使用“参考点”,我们游戏里的所有内容都能做到自动适应任何分辨率。

可视区域

前面在用内容填充屏幕时,有一个问题就是不同设备上,同一张图片能够被用户看到的内容是不同的。在 640×1136 这样的设备上,用户可以看到全部内容。而在 768×1024 这样的设备,上下被裁剪掉的内容就比较多。

能够被用户看到的内容区域,就是场景的可视区域。这个区域正好就是“虚拟分辨率”的尺寸。

由于不同设备的可视区域高度有变化,我们在设计 UI 时,就要考虑到最小可视区域问题。按照 FIXED_WIDTH 的算法,目前市面上的所有设备里,最小可视区域应该就是 iPad 了,其“虚拟分辨率”只有 640×853。

但如果死板的把 UI 局限在最小可视区域中,不同设备上的体验就不好,因为上下太多屏幕空间被浪费了。所以在 UI 设计时,就要让一些内容是“动态尺寸”的。

例如下面的界面中,底部的工具栏是固定高度,蓝色区域的高度则是根据虚拟分辨率计算的:

local toolbarHeight = 130 -- 工具栏高度 130
local padding       = 50  -- 所有的留白 50

-- 计算出内容区域的高度
local contentHeight = display.height - toolbarHeight - padding

由于 quick-cocos2d-x 支持“九宫格”图片,所以这类高度不确定的区域,制作起来没有任何难度,稍稍练习一下就能掌握。

美术素材的准备

在理解原理后,最后一个难点就是美术素材的制作了。

美术素材主要有两类:背景图、场景元素。

对于背景图,设计师按照 1536×2280 来制作,原因是:

  1. 640×960 的参考虚拟分辨率,背景图最大尺寸是 640×1140,翻倍后是 1280×2280。
  2. 考虑到可能会为 iPad 单独做优化,所以图片宽度放大到 1536。因为 Retina iPad 的屏幕分辨率是 1536×2048。

背景图制作时,也要考虑到最小可视区域问题,确保背景的主要内容在不同分辨率下都能够被看到。如果是比较复杂的背景,也可以分为多层叠加。

例如一张背景是由远景和近处的人物构成。那么可以将远景和人物分为两张图。远景屏幕居中显示,人物则以程序进行定位,确保任何分辨率下,人物的头部都能完整显示的。这样可以取得很好的显示效果。

场景元素的制作要麻烦一些。首先,确保最小可视区域中,能够容纳一个场景的所有内容。其次,在更大屏幕上,一些场景元素(主要是 UI)要可以拉伸。基本原则是按照 640×960 翻倍,也就是 1280×1920 的尺寸来制作。一些需要拉伸的元素则做成九宫格,或者多张图的拼接。

设计师按照 1280×1920 的分辨率制作出效果图,开发人员再根据实际情况,对部分元素进行相对定位。

设计师的图像按照 100% 尺寸导出后,还需要用 Texture Packer 等工具做进一步处理。这里的处理除了打包,最主要的就是将图像缩小为 50%。这样 1536×2280 的背景图就变成了 768×1140;1280×1920 的场景就变成了 640×960。

最终,我们仅用一套素材,就适应了所有设备。并且为 Retina iPad 和其他超高分辨率设备留下了优化的空间。

针对 iPad 的优化

由于 iPad 的屏幕宽度超过了 640,所以整个场景都会被放大一点。这样带来了两个问题:

  1. 有一些轻微的模糊。
  2. 场景上下的内容被裁剪较多。

要解决这个问题有两种方案:

  1. 以 768×1024 为参考虚拟分辨率。
  2. 单独为 iPad 设置虚拟分辨率。

第一种方法最简单。只要按照前文所述,重新计算出新的图片尺寸,并以此为基础让美术制作就可以了。不过缺点也很突出:

  1. 图片的尺寸大大增加。背景图需要制作为 1536×2728,场景元素的参考分辨率是 1536×2048。这直接导致最终生成的图片尺寸变大,占用的内存增多。光是背景图,就要增加 20%。
  2. 只有在 iPad 上才是不缩放显示,在其他所有设备上,场景都会缩小后显示。这对于一些文字内容,在手机上阅读起来就比较困难。虽然可以放大字体,但因为缩放的存在,字体也无法做到特别清晰。

考虑到手机用户远远多过 iPad 用户,我们的游戏还是以手机用户的体验为优先考虑。所以我们采用第二种方式来优化 iPad 体验。

在游戏启动时,检测到如果是 iPad,则使用 768×1024 的虚拟分辨率。这样做比较麻烦的地方就是程序要做不少调整,确保场景元素在 640x???? 和 768×1024 两种虚拟分辨率下都可以正常显示。

从实践看,熟练的开发人员一周左右就可以做好一款休闲游戏(大概就是天天爱消除那种复杂度)的 iPad 优化。美术素材方面,除了极少数 UI 元素要做一些调整或为 iPad 单独制作一份外,其他素材都可以继续沿用。对开发成本的影响极小。

要让游戏在 iPad 上启动时使用 iPad 的分辨率设置,应该在 config.lua 中加入以下代码:

CONFIG_AUTOSCALE_CALLBACK = function(w, h, deviceModel)
    if (w == 768 and h == 1024)
        or (w == 1536 and h == 2048) then
            -- iPad
            CONFIG_SCREEN_WIDTH = 768
            CONFIG_SCREEN_HEIGHT = 1024
            return 1.0, 1.0
    end
end

上述判断如果是在 iPad 上启动游戏,则使用 768/1024 作为参考分辨率,并且内容缩放为 100%,确保图像完全没有模糊。

针对超高分辨率设备的优化

Retina 显示屏幕的 iPad 和一些高端 Android 手机或平板,都提供了极高的分辨率。在这些设备上要获得最好的显示效果,就必须使用超高分辨率的素材。这也是本文前面提到美术素材制作时,为什么要求极高的分辨率。

不过因为超高分辨率的素材,游戏体积几乎是翻倍增加,这非常不利于游戏的传播。所以比较实际的做法还是单独出一个版本供用户下载,或者游戏启动后检测到超高分辨率设备,再提醒用户下载资源。

这些设备的优化对程序没什么影响,因为虚拟分辨率仍然是 640×960 为基准。只需要在程序启动时,用以下代码通知引擎使用了超高分辨率的素材:

CCDirector:sharedDirector():setContentScaleFactor(2)

处理横屏

横屏的处理其实相当简单,就是把“FIXED_WIDTH”换成“FIXED_HEIGHT”。这样虚拟分辨率里,高度就变成固定的了,而宽度根据设备发生变化。至于美术素材的制作、内容定位,和竖屏的方法完全一样。

总结

这一套方案,我们已经用在好几个游戏里面了。不管是从成本、最终效果上看,都很不错。

对于时间、预算都很紧张的小团队来说,连 iPad 优化那一步都可以放到后续版本来做。首先把大量手机用户的需求满足后,再来优化 iPad 体验。

最后,本文所述方案也完全可以用在原版 cocos2d-x 中。因为原版 cocos2d-x 也具有 FIXED_WIDTH 和 FIXED_HEIGHT 两种屏幕适配策略。

- EOF -

本文引用廖大文章,入口:http://quick.cocoachina.com/?p=1436

quick-cocos2d-x 多分辨率适配详解

时间: 2024-11-05 11:30:07

quick-cocos2d-x 多分辨率适配详解的相关文章

android屏幕适配详解

android屏幕适配详解 官方地址:http://developer.android.com/guide/practices/screens_support.html 一.关于布局适配建议 1.不要使用绝对布局 2.尽量使用match_parent 而不是fill_parent . 3.能够使用权重的地方尽量使用权重(android:layout_weight) 4.如果是纯色背景,尽量使用android的shape 自定义. 5.如果需要在特定分辨率下适配,可以在res目录上新建layout

Cocos2d之Node类详解之节点树(二)

一.声明 本文属于笔者原创,允许读者转载和分享,只要注明文章来源即可. 笔者使用cocos2d框架的cocos2d-x-3.3rc0版本的源代码做分析.这篇文章承接上篇<Cocos2d之Node类详解之节点树(一)>. 二.简介 节点 一个Node对象. 节点树 上篇文章介绍到,Node类有一个成员变量 Vector<Node*> _children,这是一个保存所有子节点的数组,因为Node类采用遍历树的方式获取子节点进行渲染,所以我管这两个东西的结合叫节点树. 三.源码详解 &

Cocos2d之Node类详解之ZOrder详解

一.声明 笔者以cocos2d框架的cocos2d-x-3.3rc0版本源码做分析.本文属于笔者原创,允许转载和分享,但请注明文章出处. 二.简介 ZOrder ZOrder顾名思义就是节点(Node对象)在Z轴上的排序,这样一来ZOrder越小就越优先显示.每个节点(Node对象)可以持有多个子节点,组成节点树(关于节点树的介绍查看<Cocos2d之Node类详解之节点树>一文).ZOder表示了节点树中每个子节点显示的优先级.值得注意的是,节点树中子节点的ZOder可能会一样,这种情况下父

Qt on Android: Qt Quick 之 Hello World 图文详解

在上一篇文章,<Qt on Android:QML 语言基础>中,我们介绍了 QML 语言的语法,在最后我们遗留了一些问题没有展开,这篇呢,我们就正式开始撰写 Qt Quick 程序,而那些问题,随着本系列文章的展开也会一一被干掉. 在开始介绍 Qt Quick 应用的基本元素之前,我们先来创建一个 HelloQtQuickApp 项目,就是经典的 Hello World 了. 笔者的教程最终会面向 Qt Quick 与 C++ 混合编程,所以我们 HelloQtQuickApp 从零开始.

Cocos2d之Texture2D类详解之将文件加载成Texture2D对象

一.声明 笔者以cocos2d框架cocos2d-x-3.3rc0版本的源码做分析.本文为笔者原创,允许转载和分享,只要注明文章出处即可. 二.简介 Texture2D类简介 Texture2D类允许开发者用图像.文本信息和简单的数据来创建OpenGL2D纹理.被创建的纹理拥有两个维度.根据开发者创建Texture2D对象方式的不同,实际图像的尺寸可能比生成的纹理的尺寸要小,而且纹理的内容是倒置的. 像素格式 在计算机图形学中,人们用每个像素在内存中的总位数以及分别存储红.蓝.绿和alpha(阿

Cocos2d之Node类详解之节点树(一)

一.声明 笔者分析的是用C++语言实现.版本号为cocos2d-x-3.3rc0的cocos2d框架的源代码.本文为笔者原创,允许读者分享和转载,只要读者注明文章来源即可. 二.简介 Node对象时场景图的基本元素,并且场景图的基本元素必须是Node对象和Node的子类对象.常见的Node类的子类有:Scene.Layer.Sprite.Menu和Label类. Node类主要实现几个特性: Node对象的 addChild(Node *child).getChildByTag(int tag)

iOS10 SiriKit QQ适配详解

原文连接 1. 概述 苹果在 iOS10 开放了 SiriKit 接口给第三方应用.目前,QQ已经率先适配了 Siri 的发消息和打电话功能.这意味着在 iOS10 中你可以直接告诉 Siri 让它帮你发QQ消息和打QQ电话了,听起来是不是很酷炫? 那么第三方应用使用 Siri 的体验究竟如何?哪些应用可以接入SiriKit?接入 SiriKit 又需要做哪些工作呢?这篇文章会为你一一解答这些疑惑. 图1 用Siri发QQ消息效果展示 2. SiriKit 简介 我们都知道 Siri 是 iph

Cocos2D研究院之CCNode详解(三)

http://www.xuanyusong.com/archives/950 上一章我们了解了cocos2d的项目路径以及工作原理,这次作者要真刀真枪地讲解代码了,咱们先来看看cocos2d最常用.也是作者认为最核心的类——CCNode. 之前说过,cocos2d的所有类都以CC开头,那么实际上这个类的名字就是Node,类如其名,这个类的实例就是一个节点.Cocos2d的类是树状继承的,而在内存中,各个实例之间也是以“树”这种数据结构相关联的.,可见树在cocos2d中的重要性,难怪某位伟人说“

Cocos2d之Action类详解

一.声明 文章中使用到的cocos2d的源代码的版本是cocos2d-x-3.3rc0. 二.主要内容 [Action类简介] 在cocos2d中,Action类是所有动作的基类.Action类继承了Ref类和Clonable类. [Action类的声明源码] 声明的源码在 CCAction.h 文件中,声明如下: /** @brief Base class for Action objects. */ class CC_DLL Action : public Ref, public Clona