接上回(译)如何在cocos2d里面使用动画和spritesheet(1)
为了获得动画效果,我们有5个步骤需要做。接下,将会一个步骤一个步骤给大家讲解。把下面的一些代码片断按顺序增加到你的init的Add the stuff from below注释后面。
1) 缓冲sprite帧和纹理
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:
@"AnimBear.plist"];
首先,调用CCSpriteFrameCache的addSpriteFramesWithFile方法,然后把Zwoptex生成的plist文件当作参数传进去。这个方法做了以下几件事:
- 寻找工程目录下面和输入的参数名字一样,但是后缀是.png的图片文件。然后把这个文件加入到共享的CCTextureCache中。(这我们这个例子中,就是加载AnimBear.png)
- 解析plist文件,追踪所有的sprite在spritesheet中的位置,内部使用CCSpriteFrame对象来追踪这些信息。
2) 创建一个精灵批处理结点
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode
batchNodeWithFile:@"AnimBear.png"];
[self addChild:spriteSheet];
接下来,创建CCSpriteBatchNode对象,把spritesheet当作参数传进去。spritesheet在cocos2d中的工作原理如下:
- 你创建一个CCSpriteBatchNode对象,通过传递一个包含所有sprite的spritesheet的名字作为参数,并把它加入到当前场景之中。
- 接下来,你从spritesheet中创建的任何sprite,你应该把它当作CCSpriteBatchNode的一个孩子加进去。只要sprite包含在spritesheet中,那么就没问题,否则会出错。
- CCSpriteBatchNode可以智能地遍历它的所有的孩子结点,并通过一次OpenGL ES call来渲染这些孩子,而不是以前每个sprite都需要一个OpenGL call,这样渲染速度就会更快。
注意:CCSpriteBatchNode以前叫做CCSpriteSheet,你可能会在一起比较老的代码里面看见它。
3) 收集帧列表
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i =1; i <=8; ++i) {
[walkAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:@"bear%d.png", i]]];
}
为了创建一系列的动画帧,我们简单地遍历我们的图片名字(它们是按照Bear1.png-->Bear8.png的方式命名的),然后使用共享的CCSpriteFrameCache来获得每一个动画帧。记住,它们已经在缓存里了,因为我们前面调用了addSpriteFramesWithFile方法。
4) 创建动画对象
CCAnimation *walkAnim = [CCAnimation
animationWithFrames:walkAnimFrames delay:0.1f];
接下来,我们通过传入sprite帧列表来创建一个CCAnimation对象,并且指定动画播放的速度。我们使用0.1来指定每个动画帧之间的时间间隔。
5) 创建sprite并且让它run动画action
self.bear = [CCSprite spriteWithSpriteFrameName:@"bear1.png"];
_bear.position = ccp(winSize.width/2, winSize.height/2);
self.walkAction = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
[_bear runAction:_walkAction];
[spriteSheet addChild:_bear];
我们首先通过spriteframe来创建一个sprite,并把它放在屏幕中间。然后,生成CCAnimationAction,并赋值给场景的walkAction属性,最后让熊来运行这个action。
最后,我们把熊加个场景中--把它当作spritesheet的孩子加到spritesheet中去。注意,如果在这里我们没有把它加到spritsheet中,而是加到当前层里面的话。那么我们将得不到spritesheet为我们带来的性能提升!!!
完成了!
就这么多!编译并运行,你将会看到一只熊欢快地在屏幕上面走动!
基于熊的移动方向改变熊的朝向
一切看起来好极了--除了我们并不想让熊自己独自一个人走之外,那太危险了!如果我们能够通过点击屏幕就可以想让熊往哪走,它就会往哪走的话,那就太棒了.
因此,在HelloWorldScene.m文件中做如下修改:
// Comment out the runAction method in the init method:
//[_bear runAction:_walkAction];
// And add this to the init method
self.isTouchEnabled = YES;
// Add these new methods
-(void) registerWithTouchDispatcher
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0
swallowsTouches:YES];
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
return YES;
}
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
// Stuff from below!
}
-(void)bearMoveEnded {
[_bear stopAction:_walkAction];
_moving = FALSE;
}
开始之前,我们先把init方法中的运行行走action的代码注释掉,因为我们并不想让熊自己动,直到我们发出指令之后,它才能动!
我也设置了层能够接收touch事件,然后实现了registerWithTouchDispatcher和ccTouchBegan方法。如果你对使用这个方法的好处感到好奇的话(为什么不使用ccTouchesBegan呢?),你可以查看《如何在cocos2d里面制作基于Tile地图的游戏教程》。(当前是英文,以后会更新)
当bearMoveEnded方法被调用的时候,我们想让熊停止任何正在运行的动画,并且设置标记为不再移动。
看到ccTouchEnded方法,那里就是待会要实现功能的地方。那儿有许多东西要实现,因此,让我把它们分解成一些小片断,一步步向众位看官道来:
1) 计算touch坐标点
CGPoint touchLocation = [touch locationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
这里没什么新东西--我们仅仅是把touch点转换成我们要使用的局部坐标系点。
2) 设置熊移动速度
float bearVelocity =480.0/3.0;
这里,我们设置了熊的移动速度。我假设熊要花3秒钟时间才能从iphone屏幕(480个像素宽)的一头移动到另一头。因此,简单地用480个像素除以3秒。
3) 计算x轴和y轴的移动量
CGPoint moveDifference = ccpSub(touchLocation, _bear.position);
接下来,我们需要计算出熊相当于x轴和y轴移动了多远。我们简单地使用touch坐标减去熊当前的坐标。这里使用了cocos2d的一个帮助函数ccpSub来实现这个功能。
4) 计算实际移动的距离
float distanceToMove = ccpLength(moveDifference);
我们需要计算出熊实际移动的距离(欧几里德距离)。cocos2d里面也提供了一个帮助函数来做这个事情,这个函数就是ccpLength,用来求一个向量的长度。
5) 计算移动需要花费的时间
float moveDuration = distanceToMove / bearVelocity;
最后,我们需要计算出熊要花费多长时间来走完这段路程,只需要拿距离除以速率就可以了。
6) 按照需要翻转动画
if (moveDifference.x <0) {
_bear.flipX = NO;
} else {
_bear.flipX = YES;
}
接下来,我们通过判断移动的差值,如果小于0,那么就不需要翻转动画,否则,就需要翻转。因为我们的原画里面,熊就是往左移动的,因此,当熊往左移动时,我们不需要翻转动画,而往右移动的时候,只需要翻转动画。
我们的第一直觉可能是用图片编辑器重新创建另一套朝向不同的熊的动画序列图,然后使用它们。但是,cocos2d里面有一种更容易的方式(也更高效)--我们仅仅翻转已经存在的图片就行了。
这种方式可行,实现上,我们只是设置了运行动画的sprite的flip属性,但是它会使所有相关的动画帧也相应地翻转。在这个例子中,当熊往右行走的时候,我们就设置熊的flipX为Yes。
7) 运行合适的action
[_bear stopAction:_moveAction];
if (!_moving) {
[_bear runAction:_walkAction];
}
self.moveAction = [CCSequence actions:
[CCMoveTo actionWithDuration:moveDuration position:touchLocation],
[CCCallFunc actionWithTarget:self selector:@selector(bearMoveEnded)],
nil];
[_bear runAction:_moveAction];
_moving = TRUE;
接下来,我们停止任何正在运行的action。(因为我们将要覆盖任何已经存在的命令,让它移动到其它地方去!)。当然,如果我们没有移动,我们也需要停止任何动画action。(防止意外情况)。如果我们已经在移动了,那么我们当然需要停止,因为这样就不会影响后面运行的action。(这段话有些绕口,大家仔细体会,就是说,我们在让一个sprite运行一个atcion之前,最好先让它停止任何已经在运行的action。)
最后,我们创建移动action,指定移动的位置,花费的时间,并且指定一个回调函数,这个函数会在熊移动到指定位置之后被调用。我们也需要记录,我们移到那个点了!
完成啦!
写了好多代码啊---但是值得,不是吗?编译并运行,然后点击屏幕,你将会看到一只熊在屏幕上面移动。
何去何从?
这里有这个教程的完整源代码。
现在,你应该知道如何在项目里面使用spritesheet了吧。你可以在你的项目中创建自己的动画,然后看看你到底能做些什么有趣的事情!just do it!