在现实生活中,当我们身处一辆快速行驶的车上,用眼睛向窗外眺望的时候,可以很清晰地感觉到离车越远的风
景移动越慢,而离车越近的风景则会移动越快的视觉差异。
这种视觉差不仅在现实生活中适用,在游戏开发中也经常对地图或者背景采取视觉差的运动规律,让游戏背景或
地图移动的时候显得更加真实。
一、视觉差效果类CCParallaxNode
在Cocos2D-X引擎中,也为开发者封装了一个视觉差效果类CCParallaxNode。
首先来看看它的创建方式:
<1> CCParallaxNode::create()
作用:创建一个视觉差效果类。
这个类的主要函数:
<1> addChild(CCNode * child,unsigned int z,CCPoint & parallaxRatio,CCPoint & positionOffset)
作用:添加一个子类“视图层”。
参数1:子类,添加一个CCNode,让其作为视觉差效果中的一个视图层。
参数2:Z轴,视觉差中的遮挡关系。
参数3:x轴、y轴的移动速率。
参数4:子类坐标。
二、项目实例
1、首先新建Cocos2D-X项目,取名为“MyCCParallaxNode”,然后在HelloWorldScene.cpp文件的init函数中添加如下代码。
[cpp] view plaincopy
1 bool HelloWorld::init()
2 {
3 bool bRet = false;
4 do
5 {
6 CC_BREAK_IF(! CCLayer::init());
7
8 CCSprite* spFont = CCSprite::create("front.png");
9 CCSprite* spMiddle = CCSprite::create("middle.png");
10 CCSprite* spFar = CCSprite::create("far.png");
11
12 CCParallaxNode * parallaxNode = CCParallaxNode::create();
13 addChild(parallaxNode);
14
15 //近景
16 parallaxNode->addChild(spFont,3, ccp(4.8f,0), ccp(spFont->getContentSize().width*0.5,spFont->getContentSize().height*0.5) );
17 //中景
18 parallaxNode->addChild(spMiddle, 2, ccp(1.6f,0), ccp(spMiddle->getContentSize().width*0.5,spMiddle->getContentSize().height*0.5+spFont->getContentSize().height*0.5) );
19 //远景
20 parallaxNode->addChild(spFar, 1, ccp(0.5f,0), ccp(spFar->getContentSize().width*0.5,spFar->getContentSize().height*0.5+spFont->getContentSize().height*0.5+spMiddle->getContentSize().height*0.5) );
21
22 CCActionInterval* go = CCMoveBy::create(8, ccp(-200,0) );
23 CCActionInterval* goBack = go->reverse();
24 CCFiniteTimeAction* seq = CCSequence::create(go,goBack, NULL);
25 parallaxNode->runAction( (CCRepeatForever::create((CCActionInterval*) seq) ));
26
27 bRet = true;
28 } while (0);
29
30 return bRet;
31 }
从以上代码可以看出,远景移动最慢。其X轴每次移动1.6个坐标,Y轴每次移动0个像素,而近景则每次移动的最快。由于CCParallaxNode添加的是CCNode,所以不仅可以添加CCSprite,也可以添加CCTMXTiledMap等CCNode子类。
2、实例效果图
cocos2d学习笔记(六)CCParallaxNode和Tile Map
分类: iOS cocos2d2012-07-26 22:03 2728人阅读 评论(1) 收藏 举报
游戏floatlayer引擎xml
如果你的游戏需要更大的场景,你就一定会用到CCParallaxNode或是tile map
我们知道,当我们移动时,我们会看到离我们越近的物体,会移动的越快,越远的物体,比如远处的山会移动的很慢,而最远处的物体,比如太阳几乎不动,这个现象叫视差,而在游戏中模仿视差,可以让玩家感觉到游戏中的角色的确是在移动。CCParallaxNode可以很容易的建立一个视差层,你可以控制每一层的视差率、位置和层级的高低。
[cpp] view plaincopy
32 parallaxNode = [CCParallaxNode node]; [parallaxNode
33 setPosition:ccp(levelSize.width/2.0f,screenSize.height/2.0f)]; float xOffset = 0;
34 // Ground moves at ratio 1,1
35 [parallaxNode addChild:BGLayer1 z:40 parallaxRatio:ccp(1.0f,1.0f) positionOffset:ccp(0.0f,0.0f)];
36 xOffset = (levelSize.width/2) * 0.3f; [parallaxNode addChild:BGLayer2 z:20 parallaxRatio:ccp(0.2f,1.0f)
37 positionOffset:ccp(xOffset, 0)];
38 xOffset = (levelSize.width/2) * 0.8f; [parallaxNode addChild:BGLayer3 z:30 parallaxRatio:ccp(0.7f,1.0f)
39 positionOffset:ccp(xOffset, 0)]; [self addChild:parallaxNode z:10];
我们可以看到z轴为40的视察率最大,20的最小,也就是说,最远的那一层在移动时只有当前层x轴移动速度的0.2倍,y轴速率之所以为1是因为这段代码只是在x轴上进行视差表现。
对了,有个小tip
[cpp] view plaincopy
40 id followAction = [CCFollow actionWithTarget:playerCharacter];
41 [layer runAction:followAction];
CCFollow可以让你的层镜头跟随target,不过这个镜头跟随会包括x轴和y轴
接下来说说tile map,软件下载地址:http://www.mapeditor.org,软件用法就不说了,比较简单,最后会生成.tmx文件,其实这个文件就是一个xml文件
创建对象方法
CCTMXTiledMap *tiledMapWithTMXFile:@"Level2TileMapiPhone.tmx"];
tile map的好处就是无论你的地图多大,内存占用只是每个不同tile的总和,所以使用tile map是非常省内存的一种做法,rpg游戏的地图一般都是用tile map
[cpp] view plaincopy
42 CCTMXLayer *groundLayer = [tileMapNode
43 layerNamed:@"RockBoulderLayer"];
44
45 // 2
46 parallaxNode = [CCParallaxNode node];
47 [parallaxNode setPosition:
48 ccp(levelSize.width/2,screenSize.height/2)];
49 float xOffset = 0.0f;
50
51 // 3
52 xOffset = (levelSize.width/2);
53 [groundLayer retain];
54 [groundLayer removeFromParentAndCleanup:NO];
55 [groundLayer setAnchorPoint:CGPointMake(0.5f, 0.5f)];
56 [parallaxNode addChild:groundLayer z:30 parallaxRatio:ccp(1,1)
57 positionOffset:ccp(0,0)];
58 [groundLayer release];
如上代码,如果tile map中有多个层,把这些层加入其他对象中时一定要先retain,然后从tileMapNode中remove,然后在进行加入操作,之后别忘了release一下,这样让他当前的持有者把控他的生命周期
cocos2d-x庖丁解牛(1):CCParallaxNode源码分析
分类: IOS开发 C/C++/汇编 Cocos2d-X2012-11-07 13:42 1326人阅读 评论(0) 收藏 举报
[cpp] view plaincopy
59 /**
60 CCPointObject用于记录CCParallaxNode孩子节点的ratio和offset属性
61 **/
62 class CCPointObject : CCObject
63 {
64 //视差速率
65 CC_SYNTHESIZE(CCPoint, m_tRatio, Ratio)
66 //在CCParallaxNode中的偏移量
67 CC_SYNTHESIZE(CCPoint, m_tOffset, Offset)
68 CC_SYNTHESIZE(CCNode *,m_pChild, Child) // weak ref
69
70 static CCPointObject * pointWithCCPoint(CCPoint ratio, CCPoint offset)
71 {
72 CCPointObject *pRet = new CCPointObject();
73 pRet->initWithCCPoint(ratio, offset);
74 pRet->autorelease();
75 return pRet;
76 }
77 bool initWithCCPoint(CCPoint ratio, CCPoint offset)
78 {
79 m_tRatio = ratio;
80 m_tOffset = offset;
81 m_pChild = NULL;
82 return true;
83 }
84 };
85
86 //CCParallaxNode构造函数
87 CCParallaxNode::CCParallaxNode()
88 {
89 m_pParallaxArray = ccArrayNew(5);
90 m_tLastPosition = CCPointMake(-100,-100);
91 }
92 CCParallaxNode::~CCParallaxNode()
93 {
94 if( m_pParallaxArray )
95 {
96 ccArrayFree(m_pParallaxArray);
97 m_pParallaxArray = NULL;
98 }
99 }
100
101 CCParallaxNode * CCParallaxNode::node()
102 {
103 return CCParallaxNode::create();
104 }
105
106 CCParallaxNode * CCParallaxNode::create()
107 {
108 CCParallaxNode *pRet = new CCParallaxNode();
109 pRet->autorelease();
110 return pRet;
111 }
112
113 void CCParallaxNode::addChild(CCNode * child, unsigned int zOrder, int tag)
114 {
115 CC_UNUSED_PARAM(zOrder);
116 CC_UNUSED_PARAM(child);
117 CC_UNUSED_PARAM(tag);
118 CCAssert(0,"ParallaxNode: use addChild:z:parallaxRatio:positionOffset instead");
119 }
120 void CCParallaxNode::addChild(CCNode *child, unsigned int z, const CCPoint& ratio, const CCPoint& offset)
121 {
122 CCAssert( child != NULL, "Argument must be non-nil");
123 //记录属性
124 CCPointObject *obj = CCPointObject::pointWithCCPoint(ratio, offset);
125 obj->setChild(child);
126 //扩容处理
127 ccArrayAppendObjectWithResize(m_pParallaxArray, (CCObject*)obj);
128
129 //当CCParallaxNode的位置不是(0,0)时添加孩子,会发生比较诡异的事情
130 CCPoint pos = m_tPosition;
131 pos.x = pos.x * ratio.x + offset.x;
132 pos.y = pos.y * ratio.y + offset.y;
133 child->setPosition(pos);
134
135 CCNode::addChild(child, z, child->getTag());
136 }
137 void CCParallaxNode::removeChild(CCNode* child, bool cleanup)
138 {
139 //删除属性
140 for( unsigned int i=0;i < m_pParallaxArray->num;i++)
141 {
142 CCPointObject *point = (CCPointObject*)m_pParallaxArray->arr[i];
143 if( point->getChild()->isEqual(child))
144 {
145 ccArrayRemoveObjectAtIndex(m_pParallaxArray, i, true);
146 break;
147 }
148 }
149 //删除node
150 CCNode::removeChild(child, cleanup);
151 }
152 void CCParallaxNode::removeAllChildrenWithCleanup(bool cleanup)
153 {
154 ccArrayRemoveAllObjects(m_pParallaxArray);
155 CCNode::removeAllChildrenWithCleanup(cleanup);
156 }
157 CCPoint CCParallaxNode::absolutePosition()
158 {
159 CCPoint ret = m_tPosition;
160 CCNode *cn = this;
161 //层层向上计算,获得绝对坐标,至于为什么需要这样,下面有段注释
162 while (cn->getParent() != NULL)
163 {
164 cn = cn->getParent();
165 ret = ccpAdd( ret, cn->getPosition());
166 }
167 return ret;
168 }
169
170 /*
171 The positions are updated at visit because:
172 - using a timer is not guaranteed that it will called after all the positions were updated
173 - overriding "draw" will only precise if the children have a z > 0
174 */
175 void CCParallaxNode::visit()
176 {
177 // CCPoint pos = position_;
178 // CCPoint pos = [self convertToWorldSpace:CCPointZero];
179 CCPoint pos = this->absolutePosition(); //获得绝对坐标
180 if( ! CCPoint::CCPointEqualToPoint(pos, m_tLastPosition) ) //dirty处理
181 {
182 //计算所有孩子相对于CCParallaxNode的位置,注意当我们移动CCParallaxNode位置时,表现出来的其实是孩子位置的改变,这种变化是本类的核心设计。
183 for(unsigned int i=0; i < m_pParallaxArray->num; i++ )
184 {
185 //
186 CCPointObject *point = (CCPointObject*)m_pParallaxArray->arr[i];
187 //例如CCParallaxNode绝对位置为100,表现出来的是孩子位置为-100,CCParallaxNode的移动我们不能感知,但孩子的位置却发生了变化。
188 //简单点就是类似于一个摄像头场景的移动,摄像头未动,风景变了
189 //如果ratio为1,则postion == offset
190 //如果ratio为(0,1),则position < offset,移动速度慢
191 //如果ratio为(1,xx),则postion > offset,移动速度快
192 float x = -pos.x + pos.x * point->getRatio().x + point->getOffset().x;
193 //同x
194 float y = -pos.y + pos.y * point->getRatio().y + point->getOffset().y;
195 //孩子的位置是通过上面两行计算出来的,因此手动设置其postion不会有任何作用
196 point->getChild()->setPosition(ccp(x,y));
197 }
198 //更新上一个位置
199 m_tLastPosition = pos;
200 }
201 CCNode::visit();
202 }