在上一章节中,我们已经将背景添加到了我们的场景中,在本章的教学中,我们将让我们的背景进行视差滚动。
所谓视差滚动就是,当我们的场景移动时,远处的背景移动较慢,而约近的背景移动越快,如此可以给人一种层次分明的感觉,这种技术被广泛用于横版2D游戏中。
cocos2d为我们封装了视差滚动类 CCParallaxNode,不过由于其不能单独改变其子节点的位置,不好实现连续滚动,所以接下来我们将自己来做连续滚动的视差效果。
首先新建一个类,继承于CCSprite,命名为ParallaxRollSprite,并在GameScene中导入其头文件。
在ParallaxRollSprite.h中导入cocos2d.h文件,并添加下列属性及方法:
#import "CCSprite.h"让我们了解一下这些属性和方法的作用,speed参数记录了该精灵移动的速度。jumpPoint参数记录了该精灵应该在什么位置进行跳跃,而offSetPoint记录了精灵要如何进行跳跃(例如:精灵A已每帧10的速度移动到了屏幕最左边到达了jumpPoint出发点,然后精灵跳跃至屏幕最右边重新开始向左运动,如此循环);
- (void) setParallaxRollWithSpeed:(float)speed jumpAtPoint:(CGPoint)jumpPoint offSetPoint:(CGPoint)offSetPoint 方法是为了方便我们设置以上参数,在.m文件中只需实现此方法即可,具体实现我相信大家都会的吧!
回到GameScene.m文件中,添加下列代码:
@interface GameScene ()
{
int speed;
}
@property (nonatomic, strong) NSMutableArray * parallaxRollSpriteBox;
@end
我们创建了一个speed成员变量,方便我们之后调整速度。一个parallaxRollSpriteBox可变数组,其作用将在下列代码中讲解,修改initBackGround方法,
- (void)initBackGround
{
_parallaxRollSpriteBox = [@[] mutableCopy];
for (int i = 0; i<2; i++) {
ParallaxRollSprite * cloud = [ParallaxRollSprite spriteWithImageNamed:@"cloud.png"];
cloud.anchorPoint = ccp(0, 0);
cloud.position = ccp(i * Screen_Size.width, 150);
[cloud setParallaxRollWithSpeed:0.01 jumpAtPoint:ccp(- cloud.contentSize.width, 150) offSetPoint:ccp(Screen_Size.width+cloud.contentSize.width, 0)];
[self addChild:cloud];
[_parallaxRollSpriteBox addObject:cloud];
}
for (int i = 0; i<6; i++) {
ParallaxRollSprite * building = [ParallaxRollSprite spriteWithImageNamed:@"buildingShadow.png"];
building.anchorPoint = ccp(0, 0);
building.position = ccp(i*180, 220);
[building setParallaxRollWithSpeed:0.015 jumpAtPoint:ccp(-180, 220) offSetPoint:ccp(180*6, 0)];
[self addChild:building];
[_parallaxRollSpriteBox addObject:building];
}
for (int i = 0; i<5; i++) {
ParallaxRollSprite * building = [ParallaxRollSprite spriteWithImageNamed:@"building.png"];
building.anchorPoint = ccp(0, 0);
building.position = ccp(i*200, 220);
[building setParallaxRollWithSpeed:0.03 jumpAtPoint:ccp(-200, 220) offSetPoint:ccp(200*5, 0)];
[self addChild:building];
[_parallaxRollSpriteBox addObject:building];
}
for (int i = 0; i<2; i++) {
ParallaxRollSprite * grass = [ParallaxRollSprite spriteWithImageNamed:@"grass.png"];
grass.anchorPoint = ccp(0, 0);
grass.position = ccp(i * Screen_Size.width, 200);
[grass setParallaxRollWithSpeed:0.06 jumpAtPoint:ccp(- grass.contentSize.width, 200) offSetPoint:ccp(Screen_Size.width + grass.contentSize.width, 0)];
[self addChild:grass];
[_parallaxRollSpriteBox addObject:grass];
}
CCSprite * ground = [CCSprite spriteWithImageNamed:@"ground.png"];
ground.anchorPoint = ccp(0, 0);
ground.position = ccp(0, 0);
[self addChild:ground];
for (int i = 0; i<15; i++) {
ParallaxRollSprite * groundMove = [ParallaxRollSprite spriteWithImageNamed:@"groundMove.png"];
groundMove.anchorPoint = ccp(0, 0);
groundMove.position = ccp(i * 60, 160);
[groundMove setParallaxRollWithSpeed:0.4 jumpAtPoint:ccp(-60, 160) offSetPoint:ccp(60*15, 0)];
[self addChild:groundMove];
[_parallaxRollSpriteBox addObject:groundMove];
}
}
代码比较长让我们直接在代码中来看看我们做了些什么,首先我们初始化了上面提到的可变数组用于存放我们的背景元素,其次每个背景元素都被额外放置了一次,因为如果我们每个背景只填满一个屏幕的话,背景是无法做到连续滚动的,把代码做以上修改以后,运行你的程序你会发现界面和之前还是一样,并没有开始滚动,别急,现在万事俱备只欠东风,东风来也!继续添加下列方法:
- (void)update:(CCTime)delta
{
int realSpeed = delta/(1/60.0)*speed;
for (ParallaxRollSprite * parallaxRollSprite in _parallaxRollSpriteBox) {
parallaxRollSprite.position = ccp(parallaxRollSprite.position.x - parallaxRollSprite.speed * realSpeed, parallaxRollSprite.position.y);
if (parallaxRollSprite.position.x < parallaxRollSprite.jumpPoint.x) {
parallaxRollSprite.position = ccpAdd(parallaxRollSprite.position, parallaxRollSprite.offSetPoint);
}
}
}
cocos2d v3.x版本中,场景每一帧都会自动调用该方法,我们先使用之前设定的速度speed与当前帧延迟delta计算出当前帧背景移动的速度,然后我们遍历parallaxRollSpriteBox数组,让里面的每个元素都按照其之前设置的速度倍率进行移动,由于我们的背景是水平向左移动,所以只需要查看背景位置的X坐标值是否小于触发点的X坐标值,如果满足条件就让背景当然的位置加上之前设置好的偏移量。这样我们就实现了背景的循环滚动。如果一切顺利,现在运行你的程序,你可以看到你的背景开始以不同的速度开始滚动了!
好了,今晚先写到这里,如有疑问请回复或者站内信!下一章我们将继续完成我们的FlappyBird!