《Cocos2d 跨平台游戏开发指南(第2版)》一1.11 添加视差效果

简介:

本节书摘来异步社区《Cocos2d 跨平台游戏开发指南(第2版)》一书中的第1章,第1.11节,作者: 【印度】Siddharth Shekar(谢卡)译者: 武传海 责编: 胡俊英,更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.11 添加视差效果

在本部分,我们将向游戏中添加视差效果(背景滚动效果),它是游戏中非常流行的一种效果。在视差效果中,相比于背景中的对象,前景中的对象移动得更快,背景中的对象移动得要慢很多,借此产生立体感与运动错觉。

1.11.1 准备工作

回想一下以前的电影片段,其中的英雄或主角保持静止不动,他们看上去就像在骑马一样,背景不断循环,让人产生错觉,以为英雄在场景中真地向前移动,如图1-31所示。


1_31

下面我们将实现一个非常简单的视差效果,其中所有的背景对象(例如,树、灌木、草)都以相同的速度进行移动。为了实现这一效果,我们只要获取背景图像,并让它在一个循环中不断移动即可。

视差效果实现如下:针对背景图像,我们将使用两个精灵,而不是一个精灵,在游戏开始时把它们沿水平方向并排放在一起,如图1-31中的第一幅图所示。第一个精灵可见,第二个精灵在屏幕之外,最初玩家并不能看到它。

当游戏开始时,两个精灵将以一定的速度朝x轴的负方向移动,即向屏幕左侧移动。两个精灵以相同的速度移动,因此当游戏开始时,精灵1将慢慢地向左逐渐移出屏幕,随之精灵2将一点点地在屏幕显现出来。

一旦精灵1完全移出屏幕,它将快速移到精灵2的右侧,即精灵2在游戏开始时所处的位置上。

上述过程将在一个循环中不断重复进行。两个精灵总是向屏幕左侧移动。当一个精灵从屏幕左侧移出屏幕之后,它将立即移动到屏幕右侧,并且继续向左一点点地移动。

在为视差滚动创建资源,编写视差效果代码时,有几点需要各位牢记。首先,当为视差效果创建资源时,所使用的图像应该是连续的。例如,当你观看前面的第二幅图像时,会看到背景中的山脉好像是连续的。即使Sprite 1与Sprite 2是两幅不同的图像,当把它们放在一起时,它们看上去就像单独的一张图像。同样的现象也出现在山脚下的淡绿色灌木丛上。灌木丛的左半部分位于Sprite 1中,右半部分位于Sprite 2中,当把它们并排在一起时,它们就会一起组成一棵完整的灌木,让人产生一种它们本来就是一棵单独灌木的错觉。

第二点要注意的是图像之间的接缝。即使把图像无缝衔接在一起,并且让精灵以相同的速度移动,有时在精灵之间仍然可能会观察到有缝隙存在。尽管这不是一个非常普遍的问题,但是在一些框架中它可能会出现。为了防止出现这一问题,你可以把图像稍微拉伸一点点,使图像精灵彼此略微发生重叠,通常玩家觉察不到这种细微的变化。另一个方法是采用手工方式把精灵放置到屏幕精灵的末端,并且必要时做适当的调整,把精灵之间的接缝弥合。

上面这些就是视差滚动效果背后涉及到的主要理论。接下来,让我们一起编写代码,实现简单的视差滚动效果。

1.11.2 操作步骤

首先,采用类似于创建Hero类的方式,创建CocosTouchClass类型的文件,并且将其命名为ParallaxSprite。

打开ParallaxSprite.h文件,添加如下代码。

#import "CCSprite.h"

@interface ParallaxSprite :CCSprite{

  CGSize _winSize;
  CGPoint _center;
  CCSprite *_sprite1, *_sprite2;
  float _speed;
}

-(id)initWithFilename:(NSString *)filename Speed:(float)speed;
-(void)update:(CCTime)delta;

@end

在上述代码中,我们先创建了几个变量,这些变量后面会用到,例如变量_winSize和_center,前一个变量用来获取游戏运行设备的屏幕分辨率的大小,后一个用来计算屏幕中心。

接着,我们又创建了两个CCSprite类型的变量,持有两张图像,在视差效果中用来不断循环。

然后,我们添加了一个_speed变量,用来指定图像移动与循环的速度。

类似于Hero类,在ParallaxSprite类中,我们也创建了一个initWithFilename函数,它使用给定的文件名对类进行初始化。另外,我们也添加了一个float类型变量,用来指定精灵的速度。

此外,我们还需要一个update函数,它在 1 秒内会被调用60次,用来在类中更新两个精灵的位置。

以上就是ParallaxSprite.h文件的所有代码,接下来,转到并打开ParallaxSprite.m文件。

在ParallaxSprite.m文件中,添加如下代码:

#import "ParallaxSprite.h"

@implementation ParallaxSprite

-(id)initWithFilename:(NSString *)filename Speed:(float)speed;{

  if(self = [super init]){

    NSLog(@"[parallaxSprite](init) ");

    _winSize = [[CCDirectorsharedDirector]viewSize];

    _center = CGPointMake(_winSize.width/2, _winSize.height/2);

    _speed = speed;

    _sprite1 = [CCSpritespriteWithImageNamed:filename];
    _sprite1.position = _center;
    [selfaddChild:_sprite1];

    _sprite2 = [CCSpritespriteWithImageNamed:filename];
    _sprite2.position = CGPointMake(_sprite1.position.x + _winSize.
width
, _center.y);
    [selfaddChild:_sprite2];

  }
return self;
}

在上述代码中,我们首先实现initWithFilename函数。在initWithFilename函数中,先初始化超类,获取_winSize。接着,通过把窗口的宽度与高度分别除以2计算出屏幕中心,再把speed的值赋给_speed变量。

然后,创建_sprite1和_sprite2两个变量,在spriteWithImageNames中,通过filename变量传入文件名字符串。

请注意,_sprite1被放置到屏幕中心,_sprite2被设置到屏幕之外,横坐标与_spirte1相差一个屏幕宽度,纵坐标与_spirte1相同。

最后,把两个精灵添加到类中。

接下来,我们开始实现update函数,添加代码如下:

-(void)update:(CCTime)delta{

  floatxPos1 = _sprite1.position.x - _speed;
  floatxPos2 = _sprite2.position.x - _speed;

  _sprite1.position = CGPointMake(xPos1, _sprite1.position.y);
  _sprite2.position = CGPointMake(xPos2, _sprite1.position.y);

  if(xPos1 + _winSize.width/2 <= 0){

    _sprite1.position = CGPointMake(_sprite2.position.x +
_winSize.width, _center.y);

}else if(xPos2 + _winSize.width/2 <= 0){

    _sprite2.position = CGPointMake(_sprite1.position.x + _winSize.
width
    , _center.y);
  }
}

@end

首先,我们分别为两个精灵计算它们在x轴上的新位置,计算时先获取精灵当前位置的x值,再用它减去精灵的移动速度。之所以这样做,是因为我们希望在每次调用update函数时让精灵沿着x轴的负方向进行移动。

接着,我们把新坐标分别指派给两个精灵,其中x值为上面计算得到的值,y值保持原值不变。

然后,检测图像的右边缘对于玩家是否仍然可见,还是已经移出屏幕左侧之外。如果是这样,我们就把精灵放到脱屏位置上,即纵坐标不变,横坐标与另一个精灵相距一个屏幕宽度,以确保两个精灵之间不会出现缝隙。

在代码中,我们使用了if-else语句,这是因为每次只会有一个精灵移出屏幕左侧边界。

1.11.3 工作原理

下面让我们一起看一下如何使用ParallaxSprite类。在MainScene.h类中,引入ParallaxSprite.h文件,创建一个ParallaxSprite类型的变量pSprite,代码如下:

#import "Hero.h"
#import "ParallaxSprite.h"

@interface MainScene :CCNode{

CGSizewinSize;
    Hero* hero;
ParallaxSprite* pSprite;

}

然后,在MainScene.m文件中,移除本章开始时用来添加背景精灵的代码,添加如下代码:

//Basic CCSprite - Background Image - REMOVE
//CCSprite* backgroundImage = [CCSpritespriteWithImageNamed:@"Bg.
png"];
//backgroundImage.position = CGPointMake(winSize.width/2,
winSize.height/2);
//[self addChild:backgroundImage];

//Parallax Background Sprite - ADD
pSprite = [[ParallaxSpritealloc]initWithFilename:@"Bg.png" Speed:5];
[selfaddChild:pSprite];

正如前面我们所做的那样,我们把Bg.png文件指派给pSprite,此外,我们又指定了速度值为5。

请注意,不必手工调用ParallaxSprite类的update函数,每一帧它都会被自动调用执行。而且,你也不必像以前那样调度它,开始时update函数会被自动初始化。

到此为止,我们已经编写好了所有代码,运行代码,我们将会看到如图1-32所示的背景滚动效果。


1_32

相关文章
|
Android开发 开发者 iOS开发
《Cocos2d 跨平台游戏开发指南(第2版)》一导读
自从2007年创始以来,Apple App Store一直保持着持续增长的势头,每天平均约有500个App提交。其中,大约80%的App是游戏。形成这种局面的部分原因是Apple构建了一个非常棒的生态系统,免费提供操作系统和IDE开发环境,便于普通开发者接触并使用它们。
1561 0

热门文章

最新文章