2.【cocos2d翻译系列】Beginner's Guide-Lesson2:Your first game

来源:互联网 发布:服务器网络拓扑图 编辑:程序博客网 时间:2024/06/05 05:47

Lesson2:你的第一个游戏

通过学习本篇教程,你将会创建一个新的cocos2d项目,还会添加一些精灵,并且使精
灵能够自动动起来或者是响应触摸事件才动起来。

请确保你在开始前已经完全明白了第一篇教程,Lesson1.install & Test和cocos2d的基本概念


  • 初始化设置

根据教程1中的描述,你应该从创建一个“cocos2d-(版本)应用”的模板项目开始。取个名字叫“Lesson1”并且存在你喜欢的地方,然后运行一下以确保此项目能像预期的那样正常显示“Hello World”。

现在你可能会注意到,程序启动画面是一个cocos2d的图片,并且你点击模拟器的Home键退出示例程序的时候,你就会看到程序图标也是一个cocos2d的图标。出现这种情况是因为在你的项目资源文件中有一些“特殊名称”的图片,找到那些图片看一看,因为最终你将会用自己的图片替换它们(并且这个位置也是你添加背景图片和精灵图片的地方)

(如果你现在就想替换启动画面的图片或者程序图标,只需用新的同样大小的图片替换掉磁盘上原来的图片,并修改图片的名字为"Default.png"和"icon.png",如此而已。)

让我们用这种方法添加一些附加的图片吧,为了使用精灵,保存右侧的图片(原文的右侧有个图片,不过我没有添加过来,自己随便找一张png各式的就可以了)到你项目的资源文件夹中,命名为"seeker.png"。现在切换回Xcode,然后查看资源文件夹,你会发现没有 seeker.png 这张图片。仅仅添加一张文件到磁盘上的资源文件夹,但它不会自动添加到项目中,从磁盘上的资源文件夹中将图片拖到Xcode项目里地资源文件夹中,一个带有几个选项的对话框将会出现“你可以不去管它们,默认就可以”,点击"Add"。现在你项目的资源文件夹中就会有seeker.png了。

这篇教程我们需要两个精灵,但为了简洁起见,就使用一张已经包含到项目中的图片icon.png作为我们的第二个精灵吧。


  • 创建一个精灵 

现在展开包含类的文件夹。那里有四个文件,代表了两个类:HelloWorldScene和Lesson1AppDelegate(在新的模板版本中,使用的是HelloWorldLayer和AppDelegate)。我们要做的事就是在HelloWorldScene.m中编写代码,所以选中这个文件。

我们需要做得第一件事就是要找到我们的精灵。如果我们仅仅是在一个函数中使用它,那么用一个本地变量就可以,但是如果这是很少数的情况。我们要对触摸事件做出反应让一些精灵来回移动,然后根据一些逻辑让其他精灵移动。所有这些使多个函数要使用同一个精灵成为必然。

有好几种方法可以实现多个函数使用同一个精灵。绝大多数的示例程序代码使用的方法是,当你将精灵添加到layer(层)上时,给每个精灵赋一个数值“tag”。这样你就可以通过使用getChildByTag函数查找对应的精灵了。这是一种安全的方法,但是会产生大量额外的工作,并且在一个有着数百个精灵的大游戏中这变成一个性能问题。

所以,我们会使用一种更简单地方法,这种方法是足够安全的,前提是你不能有多个scene的实例同时运行。我们仅仅是要声明一个文件范围之内的变量指向精灵。所以在文件的上方,“#include”的下方添加如下两行代码:

CCSprite *seeker1; CCSprite *cocosGuy;

这样我们就获得了两个CCSprite的指针,它可以关联到精灵对象。最初他们不会关联到任何东西,随之我们可以在"init"函数中修改它。

找到一个名字为“-(id)init”的函数。这个函数会在scene创建的时候自动调用(事实上,主layer就在scene中)。init函数中的代码可能会让你迷惑,那只是一种固定写法,不要过度在意那些东西。我们所要做得所有修改都在if语句块中

删除if语句块中的现有内容(那些代码创建“Hello World”的label(标签))我们已经不需要了。
用下面这些代码替代他们:

// create and initialize our seeker sprite, and add it to this layerseeker1 = [CCSprite spriteWithFile: @"seeker.png"]; seeker1.position = ccp( 50, 100 );[self addChild:seeker1];// do the same for our cocos2d guy, reusing the app icon as its imagecocosGuy = [CCSprite spriteWithFile: @"Icon.png"]; cocosGuy.position = ccp( 200, 300 );[self addChild:cocosGuy];

我们为每个精灵添加了3行代码。第一行代码调用了 spriteWithFile,用图片创建一个新的精灵对象。

下一行是设置精灵的位置在的中央,使用 宏"ccp"用一对儿xy坐标创建了一个二维的坐标点(实际上就是CGPoint结构体)。注意在cocos2d中x坐标轴从屏幕左边开始向右为正,y坐标从屏幕下方开始,向上为正。
最后,看看第三行每个精灵都调用了“addChild”方法添加一个新的精灵到layer中。
保存并且运行你的代码,结果就会想你看到这样:


  • 让精灵动起来


现在你已经知道怎样让精灵出现在屏幕上了,不过你可能还想让精灵来回移动。这里有两种基本的实现方法
1.使用 Action 告诉精灵在一个确定的时间后自动的移动到目标位置。
2.自己实现一个函数可以移动精灵并且在游戏里调用

让我们首先使用第二种方法吧,回到你的HelloWorldScene.m文件的init函数中。在if语句块中你创建精灵的代码那里,我们要做的就是多添加几步初始化:安排一些定期执行的回调函数。将下面代码加入到if语句块中的“[self addChild:cocosGuy];”的下面。

// schedule a repeating callback on every frame[self schedule:@selector(nextFrame:)];


意思就是调用自己(HelloWorld CCLayer)上面的"schedule"函数,并且传入一个参数,那个参数就是我们想要定期调用得函数的地址,现在还没有那个方法,好吧,我们正要创建它呢。找到空白的一行然后写下如下代码:

- (void) nextFrame:(ccTime)dt {    seeker1.position = ccp( seeker1.position.x + 100*dt, seeker1.position.y);    if (seeker1.position.x > 480+32)     {        seeker1.position = ccp( -32, seeker1.position.y );     }}

这个产生的影响就是动画的每一帧,cocos2d库都会调用你的“nextFrame”并且传入最后一帧所花费的时间(单位秒)。这是一个好机会可以处理各种事:移动精灵,碰撞检测,更新物理模型(使用物理引擎),产生大量新的敌人,删除不需要的精灵等等。

我们这里所需要做得就是移动"seeker1"这个精灵,为了移动精灵,你仅仅需要给它的坐标赋一个新值(你不可以只为一个x坐标或者一个y坐标赋值,这个不起作用的,你需要为整个坐标赋值)

我们增加精灵的x坐标100*dt这么多(它的意思就是一秒钟,精灵会移动100像素)。这种技巧期望通过dt获得恒定的速度,即使刷新频率有一点点变化,也不碍事。这是一种移动大量精灵的好办法

下面我们检测精灵是否跑出屏幕的范围,我们假设这里用的是iPhone,480像素宽,为了你的代码更通用你应该调用[[CCDirector sharedDirector]winSize]来获得屏幕的真实尺寸,但是现在情况就是480像素,并且我们添加32像素(这个精灵宽度),所以当超过480+32像素时,整个精灵就会跑出屏幕的右侧。当发生精灵跑出屏幕右侧时,我们重新设置x坐标为-32,让精灵在屏幕最左侧恰好看不到的地方。


  • 触摸回应

事件处理和定时回调函数有点不同。事件包括:在屏幕上触摸和加速计读取,它们都有指定的并且已经定义好的方法了(就触摸事件而言,有两种不同的是处理方法“standard”(标准)和“targeted”(针对性的)。请看 触摸代理 更加深入地讨论这个问题)

由于这篇教程的目的,我们使用targeted代理的方式。这就需要修改几处代码。首先,在文件开头处,import之后的位置,添加代码如下:

#import "CCTouchDispatcher.h"

现在找一个地方我们要写一个新的函数,假定在init函数后面。如果我们要使用targrted触摸方式,需要调用CCLayer的代码,设置触摸事件:

-(void) registerWithTouchDispatcher {    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];}

下一步,找到init函数,在if语句块结束之前的位置,插入一行代码允许layer上的触摸事件:

self.isTouchEnabled = YES;

现在找到一块空闲的地方在写一个新的函数,假定在函数nextFrame之后。因为我们使用了"targeted"触摸事件,所以我们至少要实现ccTouchBegin函数,并且让要返回YES,这样才能调用到你声明的触摸事件派发器:

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {     return YES;}

这样将会使另一个触摸事件代理函数被调用,让我在其中添加一些代码用来在触摸结束时移动我们的两个精灵

- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {    CGPoint location = [self convertTouchToNodeSpace: touch];    [cocosGuy stopAllActions];    [cocosGuy runAction: [CCMoveTo actionWithDuration:1 position:location]];}

convertTouchToNodeSpace为我们做了一系列工作:
1.首先它获得了view上的触摸坐标点
2.然后他使用CCDirector将坐标转化为GL的坐标
3.最后它将GL的坐标转化为node坐标(这里的node就是CCLayer)
然后我们做下面这些事情:
1.我们停止前面对cocosGuy要做的一切Actions
2.最后,我们运行一个新的action,他在1秒钟内移动cocosGuy这个精灵到触摸点。
注意我们不需要在nextFrame中添加任何代码来让精灵移动,因为我们使用actions替代了它。

运行app并且实验一下你将会发现当你手指离开屏幕时(或者说你的鼠标离开模拟器)cocos2d的图标就会快速地经过那个位置,然后这个精灵seeker又会继续一直快速横穿屏幕。

当你准备好时,学习 Lesson 3. Menus and Scenes.

原创粉丝点击