iOS 7新引入的Sprite Kit类库算是给iOS游戏开发者带来一些福音吧,由于是用底层的东西做开发,在效率方面应该会有很大的提高。也不单单是在游戏方面,任何需要动画效果的app也可以利用Sprite Kit来实现。
每天抽点时间出来学习一下,做一下笔记,今天是第一次学习笔记,先跟大家总体的介绍一下整个Sprite Kit框架,接下来会利用官方的例子带大家进入Sprite Kit。学过cocos2d的朋友可能会学得比较快,其实很多东西都是相通的,有关cocos2d的东西就不多说。
如上图所示,这是每一帧会做的事情,更新每一帧的内容,然后是场景中的行为,再就是物理系统,最后通过SKView进行渲染。可以通过一个UIviewController,将其view object的class属性由UIView改为SKView,然后在上面做你想要渲染的东西,可以通过storyboard对其view进行修改,有了SKView之后就需要SKScene了,再场景中添加你要的游戏对象,这不难理解吧。Sprite Kit好像没有Layer的概念,可以直接在Scene上面直接画东西,SKSpriteNode便是你要在Scene上面呈现的精灵,另外添加文本为SKLabelNode,同样继承SKNode,建议大家去了解一下整一个的Node Tree。
大概的框架逻辑就是,在Sprite View上添加Sprite Scene,Sprite渲染在Scene上,Node Tree展示了所有可以出现在Scene上的东西,node可以执行action,Scene上有物理系统
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
SKScene * scene = [SKMainScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
好了,有了一个大概了解之后,开始用例子了来学习Sprite Kit
直接创建一个工程
配置工程
首先当然是建立工程,Xcode8提供了SpriteKit模板,使用该模板建立新工程,名字就叫做SpriteKitSimpleGame好了。
运行后你会看到一静态的Hello World
图片,如下,可以与用户交互
-
先不用理会里面的源代码,我们先新创建一个MyScene继承自SKScene,里面什么都不用做
将GameViewController.m中的-viewDidLoad:
方法全部替换成下面的-viewDidLoad:
。
- (void) viewDidLoad:(BOOL)animated
{
[super viewDidLoad:animated];
// 配置view 你会发现当前的view就是``SKView ``可以在main.storyboard中查看
SKView * skView = (SKView *)self.view;
// 显示FPS 右下角
skView.showsFPS = YES;
// 显示节点数量 右下角
skView.showsNodeCount = YES;
//创建和配置场景
SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// 呈现场景
[skView presentScene:scene];
}
运行后你会发现里面是漆黑一片,就只剩下右下角的nodes 和 fps 了
接着我们要在MyScene做点事情,重写- (instancetype)initWithSize:(CGSize)size
方法
- (instancetype)initWithSize:(CGSize)size {
self = [super initWithSize:size];
if (self) {
self.backgroundColor = [SKColor whiteColor];
}
return self;
}
运行程序你会发现界面变白了,这样显得太单调了,我们再做点事情,这里我们模仿官方示例程序让界面显示Hello World
我们在MyScene 的- (void)didMoveToView:(SKView *)view
方法里这么写
- (void)didMoveToView:(SKView *)view {
[super didMoveToView:view];
SKLabelNode *labelNode = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
labelNode.text = @"Hello World";
labelNode.fontSize = 40;
labelNode.fontColor = [SKColor redColor]; // 默认白色
labelNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
labelNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:labelNode.frame.size];
[self addChild:labelNode];
运行后你会发现如下所示
接下来我们再为文本添加一些动作实现一下动画效果,还是在.m文件里,添加如下代码:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self helloAction];
}
- (void)helloAction {
SKNode *helloNode = [self childNodeWithName:@"helloNode"];
if (helloNode != nil) {
helloNode.name = nil;
SKAction *moveUp = [SKAction moveByX:0 y:100 duration:0.5];
SKAction *zoom = [SKAction scaleTo:2 duration:0.25];
SKAction *pause = [SKAction waitForDuration:0.5];
SKAction *fadeAway = [SKAction fadeOutWithDuration:0.25];
SKAction *remove = [SKAction removeFromParent];
SKAction *moveSequence = [SKAction sequence:@[moveUp, zoom, pause, fadeAway, remove]];
[helloNode runAction:moveSequence];
}
}
这里重写了-(void)touchesBegan:(NSSet
函数,即点击屏幕便开始播放动画。定义一个动作,上面的代码写得很清楚,Sprite Kit自带的很多种,我解释一下上的各个动作吧,哦,这里说一下,可以通过name属性拿到具有相同name的node,它允许多个node具有同样的名字。第一个动作是上升100个单位,时间间隔为0.5,第二个动作是放大2倍,然后停0.5秒,接着fadeOut,最后一个是将labelNode从Scene里面移除,将这几个动作用一个队列连接起来,它便会一个接一个地播放下去,然后runAction就ok了。
运行,点击屏幕,动画开始执行,如无意外,整个HelloWorld会照着我们的动作而行动着,这时可以观察一下最下面一行nodes和draws的数量变化,动画执行完后我们发现,它停住,只剩下白色的Scene
接下来我们再做一些有意思的事情,往scene中再添加两个node
- (void)didMoveToView:(SKView *)view {
[super didMoveToView:view];
SKLabelNode *labelNode = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
labelNode.name = @"helloNode";
labelNode.text = @"Hello World";
labelNode.fontSize = 40;
labelNode.fontColor = [SKColor redColor]; // 默认白色
labelNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
labelNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:labelNode.frame.size];
[self addChild:labelNode];
NSLog(@"------%@",NSStringFromCGRect([labelNode calculateAccumulatedFrame]));
//设置边界 如果不设置边界,我们的精灵就跑到地球的另一边了
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(self.frame.origin.x, self.frame.origin.y, self.size.width, self.size.height)];
[self planeNode];
}
-(void)planeNode{
// 垃圾代码,为了省事就先不管了
SKSpriteNode *qqNode = [SKSpriteNode spriteNodeWithImageNamed:@"qq"];
qqNode.position = CGPointMake(self.size.width/2, self.size.height/2);
qqNode.anchorPoint = CGPointMake(0.5, 0.5);
qqNode.zPosition = 1;
qqNode.name = @"qq";
[self addChild:qqNode];
SKSpriteNode *qqNode1 = [SKSpriteNode spriteNodeWithImageNamed:@"qq"];
qqNode1.position = CGPointMake(self.size.width/2+100, self.size.height/2);
qqNode1.anchorPoint = CGPointMake(0.5, 0.5);
qqNode1.zPosition = 1;
qqNode1.name = @"qq1";
[self addChild:qqNode1];
}
运行后你会看到如下界面
-
SKNode类中有一个属性叫physicsBody,这个physicsBody属性就是用来指定对象的物理体的.下面我们就用代码来给我们的精灵添加矩形物理模型.添加的过程是在touchBegan中实现的.全部代码如下.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self qqAction];
}
- (void)qqAction {
// 根据node的name取出node
SKSpriteNode *qqNode = (SKSpriteNode *)[self childNodeWithName:@"qq"];
// 设置node 的 物理边界
qqNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:qqNode.size];
// 设置反弹力
qqNode.physicsBody.restitution = 0.1;
// 在物体的(0,0)点上施加一个拉力
[qqNode.physicsBody applyForce:CGVectorMake(1000, 200) atPoint:CGPointMake(0, 0)];
SKSpriteNode *qqNode1 = (SKSpriteNode *)[self childNodeWithName:@"qq1"];
qqNode1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:qqNode1.size];
qqNode1.physicsBody.restitution = 0;
[qqNode1.physicsBody applyForce:CGVectorMake(1000, 100) atPoint:CGPointMake(0, 0)];
}
然后运行程序,哇,变得有意思点了不是吗