注:本文译自Sprite Kit Tutorial: Animations and Texture Atlases
从本文,可以学习到如何使用iOS 7中的Sprite Kit框架创建一个简单的动画:在屏幕上行走的熊。
另外还可以学习到如何使用纹理图集来制作动画效果,如何在触摸事件发生时让熊移动,以及改变熊运动的方向。
学习本文之前,最好先看看下面的文章: Sprite Kit教程:初学者 1 Sprite Kit教程:初学者 2 Sprite Kit教程:初学者 3
英文原文在这里:Sprite Kit Tutorial for Beginners
下面我们就开始吧。
我们先创建好一个工程架子——选择File\New Project…,在iOS Application中选择Sprite Kit Game,如下图所示:
选择Next,并将工程命名为AnimatedBear,把Class Prefix中的内容清除掉,并将Devices选择为iPad,如下图所示:
接着选择Next,将工程保存到磁盘中。
现在编译并运行程序的话,当点击屏幕时,可以看到在屏幕中有一个自动旋转的飞船。如下图所示:
这样工程架子就准备好了,下面我们去寻找一些熊的动画资源——从这里下载即可:BearImages Art。如下图所示:
上面下载到的图片有所需要的最大分辨率——iPad retina显示(2X)和non-retina版本(1x)。这些文件的命名方式为bear1..n@2x~ipad和bear1..n~ipad.png。
在这里,构建一个动画,你可以只需要将这些图片直接添加到Sprite Kit工程中即可。不过,还有另外一种更加方便的方法来构建动画——使用纹理图集。
如果之前你没使用过纹理图集,那你可以把它想象为一副很大的图片,其中包括动画中需要使用到的各种图片。这个图集可以看做是一个文件,它指定了每个sprite的边界范围,当在代码中需要使用时,可以将这些sprite取出来。
使用纹理图集是因为Sprite Kit和图形引擎会对其做相应的优化处理。后面这段话暂时不知道什么意思:
1 |
If you use sprites within a texture atlas properly, rather than making one OpenGL ES draw call per sprite it just makes one per texture atlas sheet. |
简而言之——使用纹理图集会非常的快,特别是有大量sprite的时候!
Xcode会自动的生成这个纹理图集文件,并指定好每个sprite的边界范围,这样当在代码中需要用到某个sprite的时候,可以方便取出来。这一切都会自动处理,开发者不用亲力为之。
1 |
注意:当纹理图集有问题时(例如错误的图片等),那么建议clean一下工程(Product\Clean)——这样可以强制让纹理图集重新构建。 |
为纹理图集创建一个文件夹,并将图片文件放置到该文件夹中,然后在文件夹名称尾部添加.atlas。这样Xcode就能识别出.atlas扩展名,进而自动的将图片合并为一个纹理图集。
之前下载的图片资源中有一个名为BearImages.atlas的文件夹,里面包含了各种分辨率的图片(是其它两个文件夹中的图片合集)。
将名为BearImages.atlas的文件夹拖拽到程序中,如下图所示:
当释放鼠标时,会看到如下图片中的对话框:是关于如何添加到工程中的。确保选中这三项:Copy items into destination group’s folder, Create groups for any added folder, 和 the AnimatedBear,然后点击Finish:
在Xcode中展开这个文件夹BearImages.atlas,会看到如下内容:
下面,是时候让熊动起来了!
这里我们先把熊显示在屏幕中间,并开启永久循环动画。
此处主要都是在MyScene.m中写代码。打开这个文件,并用下面的代码替换之:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#import <AVFoundation/AVFoundation.h> #import "MyScene.h" @implementation MyScene { SKSpriteNode *_bear; NSArray *_bearWalkingFrames; } -(id)initWithSize:(CGSize)size { if (self = [super initWithSize:size]) { /* Setup your scene here */ self.backgroundColor = [SKColor blackColor]; // TODO... } return self; } -(void)update:(CFTimeInterval)currentTime { /* Called before each frame is rendered */ } @end |
上面的代码很简单,只是定义了几个稍后会用到的变量。编译并运行一下,确保没有错误——会看到屏幕是黑色的。
接下来要让熊动起来,有5步需要处理,我们就来看看吧。
记得将下面的代码添加到initWithSize方法的TODO位置。
1) 构建一个用于保存行走帧(walking frame)
1 |
NSMutableArray *walkFrames = [NSMutableArray array]; |
2) 加载纹理图集
1 |
SKTextureAtlas *bearAnimatedAtlas = [SKTextureAtlas atlasNamed:@"BearImages"]; |
上面的代码会从程序bundle的数据区中创建一个图集。Sprite Kit会根据设备的寻找对应分辨率的图片文件,在iPad retina上会使用BearImages@2x~ipad.png。
3) 构建帧列表
1 2 3 4 5 6 7 |
int numImages = bearAnimatedAtlas.textureNames.count; for (int i=1; i <= numImages/2; i++) { NSString *textureName = [NSString stringWithFormat:@"bear%d", i]; SKTexture *temp = [bearAnimatedAtlas textureNamed:textureName]; [walkFrames addObject:temp]; } _bearWalkingFrames = walkFrames; |
上面的代码根据图片名称从图集中循环获取到一个帧列表(这些图片的命名为bear1.png->bear8.png),注意到numImages这个变量了吗?它为啥要除以2呢?
这是因为:纹理图集包含了所有分辨率的图片文件(non-retina和retina)。共有16个文件,每种分辨率有8个文件。要想加载某种分辨率的图片,就需要除以2。这样通过名称和计数器,就能获取到正确的分辨率图片。
4) 创建sprite,并将其位置设置为屏幕中间,然后将其添加到场景中
1 2 3 4 5 |
SKTexture *temp = _bearWalkingFrames[0]; _bear = [SKSpriteNode spriteNodeWithTexture:temp]; _bear.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)); [self addChild:_bear]; [self walkingBear]; |
利用帧列表的第一帧构建一个sprite,然后将其放置到屏幕正中间。最后调用walkingBear方法,让熊开始走动。
5) 在initWithSize方法后面添加一个新的方法walkingBear
1 2 3 4 5 6 7 8 9 10 |
-(void)walkingBear { //This is our general runAction method to make our bear walk. [_bear runAction:[SKAction repeatActionForever: [SKAction animateWithTextures:_bearWalkingFrames timePerFrame:0.1f resize:NO restore:YES]] withKey:@"walkingInPlaceBear"]; return; } |
上面的这个action会以0.1秒的间隔开始播放各帧。如果你的代码再次调用这个方法使动画重新开始的话,walkingInPlaceBear这个key会强制移除动画。这对于确保动画不相互干扰非常重要。withKey参数还提供了一个钟方法对动画进行检查,来判断其是否通过名称运行的。
这个action是永久重复的,内部的actionan imateWithTextures会按顺序动画播放帧列表中的图片。
完工!
现在编译并运行程序,一切正常的话,会在屏幕中看到一个会动的熊,如下图所示:
……Sprite Kit教程:动画和纹理图集 1 结束……