五.多分辨率自适应的实现
首先我们要设置我们的适配模式为kResolutionFixedHeight:
1
|
pEGLView
->
setDesignResolutionSize
(
960
,
720
,
kResolutionFixedHeight
)
;
|
假定我们的游戏为分辨率(960,720)的横版游戏,至于为什么是960×720,最后再告诉大家,这里且让小弟卖个关子!
1.背景层
对于背景层来说这个问题So Easy,我们只用准备一张比设计分辨率长很多(或高很多,取决于你游戏的方向,另一个方向的尺寸和设计尺寸相同!)的图片即可!
这里我们随便找张素材:
大家在hellocpp工程中的HelloWorld::init函数末尾加入如下代码:
1
2
3
|
CCSprite
*
pSprite
=
CCSprite
::
create
(
"background.jpg"
)
;
pSprite
->
setPosition
(
ccp
(
visibleSize
.
width
/
2
+
origin
.
x
,
visibleSize
.
height
/
2
+
origin
.
y
)
)
;
this
->
addChild
(
pSprite
,
0
)
;
|
下图是的main.cpp中设置的窗口大小为标准960×720和其他分辨率下的效果:
哈哈哈,看我们的设计区域是不是都被完整的显示出来了呢?大家可以用(上)文章中提到的分辨率挨个试一遍,都是没有问题的!(Yes,妈妈再也不用担心我的多分辨率适配了!)
2.游戏内容
关于这部分的内容,太多太复杂,真的不好讲啊!我简单讲来一下,要有什么不懂得,请在评论中说明或者@justbilt私信给我,我会在第一时间回复的!我们需要一个节点(CCNode),用来将游戏的所有内容都添加到上面,再将这个节点添加到屏幕的中心! 这个节点可以是CCLayer,CCNode,或者CCTMXTiledMap都行!这里要注意以下几点:
1).选择根节点
如果根节点选择的是CCLayer,CCNode之类的,要去设置它们的setContentSize(designResolutionSize);
1
2
3
4
5
|
CCNode
*
pGameRoot
=
CCNode
::
create
(
)
;
pGameRoot
->
setAnchorPoint
(
ccp
(
0.5f
,
0.5f
)
)
;
pGameRoot
->
setPosition
(
ccp
(
visibleSize
.
width
/
2
+
origin
.
x
,
visibleSize
.
height
/
2
+
origin
.
y
)
)
;
pGameRoot
->
setContentSize
(
designResolutionSize
)
;
addChild
(
pGameRoot
)
;
|
如果根节点是自身CCTMXTiledMap(注:这里我们地图的内容不要超过设计尺寸),就不用进行上边的操作了!
2).坐标设置
游戏中尽量不要用绝对坐标(其实绝对坐标木任何问题),让我们加入几个精灵试试:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
//右上角
CCSprite
*
pHero
=
CCSprite
::
create
(
"hero.png"
)
;
pHero
->
setPosition
(
ccp
(
pGameRoot
->
getContentSize
(
)
.
width
,
pGameRoot
->
getContentSize
(
)
.
height
)
)
;
pGameRoot
->
addChild
(
pHero
)
;
//左下角
pHero
=
CCSprite
::
create
(
"hero.png"
)
;
pHero
->
setPosition
(
ccp
(
0
,
0
)
)
;
pGameRoot
->
addChild
(
pHero
)
;
//右下
pHero
=
CCSprite
::
create
(
"hero.png"
)
;
pHero
->
setPosition
(
ccp
(
pGameRoot
->
getContentSize
(
)
.
width
,
0
)
)
;
pGameRoot
->
addChild
(
pHero
)
;
//左上
pHero
=
CCSprite
::
create
(
"hero.png"
)
;
pHero
->
setPosition
(
ccp
(
0
,
pGameRoot
->
getContentSize
(
)
.
height
)
)
;
pGameRoot
->
addChild
(
pHero
)
;
//中心
pHero
=
CCSprite
::
create
(
"hero.png"
)
;
pHero
->
setPosition
(
ccp
(
pGameRoot
->
getContentSize
(
)
.
width
/
2
,
pGameRoot
->
getContentSize
(
)
.
height
/
2
)
)
;
pGameRoot
->
addChild
(
pHero
)
;
|
让我们看下效果:
游戏中的我们尽量使用相对坐标,可以通过以下几种方式求得:
①.相对于父亲的尺寸比例
②.相对于另一个精灵的坐标的偏移
③.相对于屏幕的尺寸的比例
这样日后修改起来了会很方便!
哈哈哈,大家可以把上段代码中的pGameRoot->getContentSize().width,pGameRoot->getContentSize().height换成960×720的绝对坐标试下,结果是没有任何问题的!
3).介绍几个坐标转换的函数
1
|
CCPoint
CCDirector
::
convertToGL
(
const
CCPoint
&
obPoint
)
;
|
将UI坐标(左上角为原点)转化为OpenGL(左下角为原点)坐标,CCTouch中的坐标为UI坐标,我们使用时要转换为OpenGL坐标
1
|
CCPoint
CCDirector
::
convertToUI
(
const
CCPoint
&
obPoint
)
;
|
将OpenGL坐标转化为UI坐标,主要用在设置CCTouch的触点(讲触摸的那篇文章有提到)!
1
2
3
|
CCPoint
CCNode
::
convertToNodeSpace
(
const
CCPoint
&
worldPoint
)
;
CCPoint
CCNode
::
convertToWorldSpace
(
const
CCPoint
&
nodePoint
)
;
|
世界坐标空间和Node空间的转化,请看下图:
如图,我们用中间的小人getPosition()得到的是相对与父亲的坐标(即红框),如果我们想得到它相对于原点的坐标,就可以这样:
1
|
CCPoint
worldpos
=
pHero
->
convertToWorldSpace
(
pHero
->
getPosition
(
)
)
;
|
如下图:
假如我们在红色圆圈位置点击,想判断落点在哪一格,但是我们从pTouch->getLocation();得到的坐标是相对于原点的,这样我们要减去红框(pGameRoot)的左下角坐标才行,很麻烦的,我们可以这个样子做:
1
2
|
CCPoint
touchPoint
=
pTouch
->
getLocation
(
)
;
CCPoint
touchInGameRoot
=
pGameRoot
->
convertToNodeSpace
(
touchPoint
)
;
|
哈哈哈,这样子是不是很简单?这样子touchInGameRoot就是以pGameRoot左下角的偏移量了!
游戏内容部分就讲到这里!
3.UI层
UI层的实现相对来说比较简单,目前来说大概有两种实现方式:
①.根据”米”来设设置UI控件的位置.
②.根据屏幕的%来这设置UI控件的位置.
1).让我们直接上代码吧:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
CCMenuItemImage
*
pItem
=
CCMenuItemImage
::
create
(
"red.png"
,
"blue.png"
)
;
pItem
->
setPosition
(
ccp
(
visibleSize
.
width
*
0.0f
,
visibleSize
.
height
*
0.0f
)
)
;
CCMenuItemImage
*
pItem1
=
CCMenuItemImage
::
create
(
"red.png"
,
"blue.png"
)
;
pItem1
->
setPosition
(
ccp
(
visibleSize
.
width
*
1.0f
,
visibleSize
.
height
*
0.0f
)
)
;
CCMenuItemImage
*
pItem2
=
CCMenuItemImage
::
create
(
"red.png"
,
"blue.png"
)
;
pItem2
->
setPosition
(
ccp
(
visibleSize
.
width
*
0.0f
,
visibleSize
.
height
*
1.0f
)
)
;
CCMenuItemImage
*
pItem3
=
CCMenuItemImage
::
create
(
"red.png"
,
"blue.png"
)
;
pItem3
->
setPosition
(
ccp
(
visibleSize
.
width
*
1.0f
,
visibleSize
.
height
*
1.0f
)
)
;
CCMenuItemImage
*
pItem4
=
CCMenuItemImage
::
create
(
"red.png"
,
"blue.png"
)
;
pItem4
->
setPosition
(
ccp
(
visibleSize
.
width
*
0.5f
,
visibleSize
.
height
*
0.5f
)
)
;
CCMenu
*
pMenu
=
CCMenu
::
create
(
pItem
,
pItem1
,
pItem2
,
pItem3
,
pItem4
,
NULL
)
;
pMenu
->
setPosition
(
CCPointZero
)
;
this
->
addChild
(
pMenu
,
1
)
;
|
这个是按照比例去设置UI位置的,下面是效果图,大家注意不同分辨率下红色圆饼的位置:
关于如何用”米”子来布局的实现,大家去这里看http://dualface.github.io/blog/2012/08/17/cocos2d-x-2-dot-0-multi-resolution/,这个不是我要讲的重点,毕竟手写坐标的人不会很多,我们主要讲如何在编辑器中实现UI布局的自适应!
2).在cocosbuilder中如何实现自适应
如果你用过cocosbuilder的话,你一定对下图不陌生:
这个是我们设置物体坐标的一个界面,功能介绍我引用K.C的文章中的一段话:
他讲的非常好,我就不赘述了,我们一般情况下只会使用第一个,当时为了适配多分辨率,我们不能这么做了!在这里我们还是有两种做法来实现,一个是相对布局,一个是%比,但是我推荐将两种方案结合起来.
①.相对位置负责四个角落的位置,即:左下,左上,右下.右上!
②.而中间的几个位置就只能交给%,即:上,下,左,右,中!
这里我们要注意几点(都是血淋淋的坑啊):
①.对于CCMenu,CCNode,CCSprite都能够实用上边的两个方法来设置坐标,唯独CCMenuItem不行,只能使用绝对坐标,这点大家一定要注意.那么对于下面的情况该怎么办呢:
我的解决方案是给”每一堆”按钮都添加一个CCMenu,然后CCMenuItem按照相对位置来,上图中我就使用了3个CCMenu!
②.对于要”扎堆”的控件(即控件间的相对位置保持不变),一定要加入到一个公共的父亲上!
③.灵活使用AnchorPoint属性!
六.设计尺寸的设定
之前文章中有提到设置游戏的分辨率为(960,720),那么为什么呢?
首先我们来考虑选择什么样的宽高比,宽高比越小,画面就越方,比如ipad(4:3=1.33)的宽高比就比iphone(3:2=1.5)的小,所以ipad的屏幕更方一些!因此我们设计游戏是应该按照最小的宽高比去设计,这样在大的宽高比的机型上都能够看到完整的画面,从表1中可知宽高比最小的是4:3!
下面我们来考虑分辨率,分辨率要符合大多数设备的要求,经过分析960的宽是最符合要求的,转为4:3就是960×720!.
(全文完)