《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

相关文章
|
安全 程序员 Linux
删库跑路?掌握rm命令的技巧,高效删除文件和目录!
删库跑路?掌握rm命令的技巧,高效删除文件和目录!
1023 0
|
10月前
|
机器学习/深度学习 人工智能 自然语言处理
《鸿蒙Next:让人工智能语音交互听懂每一种方言和口音》
鸿蒙Next系统通过丰富方言语音数据、优化语音识别模型、引入语音合成技术及用户反馈机制,大幅提升对不同方言和口音的识别能力。具体措施包括多渠道收集方言数据、建立动态数据库、采用深度学习算法、实现多任务学习与对抗训练、生成标准方言样本,并结合硬件如麦克风阵列技术优化语音输入质量。这些综合手段确保了语音交互的准确性和实时性,为用户提供更智能、便捷的服务。
655 16
|
消息中间件 大数据 Kafka
【建议收藏】技术人必看:如何选择适合你公司的消息队列工具
本文介绍了消息队列在系统架构中的三大作用:异步处理、削峰填谷和解耦,并通过实例详细阐述了每种作用的优势。文中推荐了三款消息队列工具:RabbitMQ适合中小型公司,因其开源和社区活跃;RocketMQ适合大型公司,因其强大的二次开发能力;而在大数据领域,Kafka是实时计算和日志采集的标准选择。作者小米鼓励读者根据自身需求选择合适的消息队列,并邀请大家探讨技术话题。
503 2
|
12月前
|
数据可视化
教育工作高效协作教程:看板工具应用实操
2分钟学会如何为你的班级搭建可视化管理看板!
179 0
教育工作高效协作教程:看板工具应用实操
|
C# Windows 开发者
超越选择焦虑:深入解析WinForms、WPF与UWP——谁才是打造顶级.NET桌面应用的终极利器?从开发效率到视觉享受,全面解读三大框架优劣,助你精准匹配项目需求,构建完美桌面应用生态系统
【8月更文挑战第31天】.NET框架为开发者提供了多种桌面应用开发选项,包括WinForms、WPF和UWP。WinForms简单易用,适合快速开发基本应用;WPF提供强大的UI设计工具和丰富的视觉体验,支持XAML,易于实现复杂布局;UWP专为Windows 10设计,支持多设备,充分利用现代硬件特性。本文通过示例代码详细介绍这三种框架的特点,帮助读者根据项目需求做出明智选择。以下是各框架的简单示例代码,便于理解其基本用法。
930 0
|
机器学习/深度学习 人工智能 自然语言处理
NVIDIA Triton系列03-开发资源说明
NVIDIA Triton 推理服务器是用于高效部署机器学习模型的开源工具。本文介绍了初学者如何通过官方文档和 GitHub 开源仓库获取开发资源,包括快速启动指南、生产文档、示例和反馈渠道。特别强调了核心仓库中的六个重要部分,涵盖服务器部署、核心功能、后端支持、客户端接口、模型分析和模型导航工具。这些资源有助于初学者全面了解和掌握 Triton 项目。
344 0
NVIDIA Triton系列03-开发资源说明
|
Linux
Linux下rz/sz安装及使用方法 (不需要借助ftp传输工具)
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34173549/article/details/81606337   一、工具说明       在SecureCRT这样的ssh登录软件里, 通过在Linux界面里输入rz/sz命令来上传/下载文件. 对于某些linux版本, rz/sz默认没有安装所以需要手工安装。
2362 0
|
XML JSON 缓存
携程获取景点详情 API 返回值说明
-- 请求示例 url 默认请求参数已经URL编码处理 curl -i "https://api-gw.onebound.cn/xiecheng/item_get_scenic/?key=<您自己的apiKey>&secret=<您自己的apiSecret>&num_iid=138153"
|
SQL 存储 分布式计算
安装部署--rpm 包本地 yum 源制作 | 学习笔记
快速学习 安装部署--rpm 包本地 yum 源制作
581 0
安装部署--rpm 包本地 yum 源制作 | 学习笔记