sprite kit 学习总结,以下简称sk,不要ctrl+c +v不一定运行的起
在sk中所有的动画,渲染都由skview对象执行
在skview绘制需要的内容,需要通过另一个继承于sknode(不会绘制内容)的对象skscene
skscene的所有内容是通过它来组织的 ,用场景 来描述各种内容 如:主菜单、结束画面、游戏画面等等,通过skview实现 场景的切换或者呈现
sk使用SkView 加载scene
[skView presentScene:scene];
加载过渡动画场景
[self.view presentScene:scene transition:transition ];
scene中重要的方法
-didmovetoview 场景呈现完调用的方法
- didChangeSize: 当场景大小发生改变时调用该方法
- (void)didMoveToView:(SKView *)view 参数view:持有该场景的视图返回值 论述这个方法通常会被子类重写。执行动画循环
- (void)update:(NSTimeInterval)currentTime 参数currentTime:已经过去的时间,保证单调递增返回值 不要直接调用这个方法,它每一帧会被调用一次
- (void)didSimulatePhysics它每一帧会被调用一次。场景子类应该重写这个方法,并执行一些需要的更新这是对场景变化更改最晚的一个方法
在sk中 所有的内容都是以节点树的形式呈现,一切节点都继承与sknode
常用的精灵:
skspritenode 可以用于创建一个带纹理的精灵
对于纹理的理解,现在不是很深,相当于图片,但是它不同一般的图片,这样的精灵能有更多的属性比如精灵可以再次绘制变色或者其他阴影效果
[SKSpriteNode spriteNodeWithImageNamed:@"background"]
sklabelnode 文本节点
skvideonode 视频节点,用法和avfoundation里面的类似
skemitternode 创建渲染粒子的节点(很酷炫)
NSString *path=[[NSBundle mainBundle]pathForResource:@"snow" ofType:@"sks"];
SKEmitterNode *emitternode=[NSKeyedUnarchiver unarchiveObjectWithFile:path] ;
emitternode.particleScaleRange=0.2;
emitternode.particleLifetimeRange=0.3;
emitternode.particleBirthRate=4;
emitternode.particleSpeed=0.4;
//scale 美妙0.1速度减小
emitternode.particleScaleSpeed=-0.1;
//限定 产生多少粒子,它会自动停下来
emitternode.numParticlesToEmit=40;
//使用序列改变粒子的随时间尺度属性;
SKKeyframeSequence *scalesequence=[[SKKeyframeSequence alloc]initWithKeyframeValues:@[@0.2,@0.7,@0.1] times:@[@0.0,@0.5,@0.7]];
emitternode.particleScaleSequence=scalesequence;
各种节点 在添加时有个默认锚点,也就是精灵的左下角(0,0) 横向0-1垂直方向0-1
锚点也就是对精灵的定位在哪里(比如旋转,放大缩小是以精灵那个部位作为基准的)。。。计算各种碰撞检测,添加内容到场景需要注意
添加节点内容到场景 [node add children:anode];
制作可以拉伸的精灵
gameplaynode.centerRect=CGRectMake(12/28, 12/28, 2/28, 2/28);
表示 4个角分别占12 个像素,中间扣出宽度为2像素的矩形2*2像素大小
这个的效果很有用,比如制作一个对话框,内容很多的时候,他的背景图片只有那么大
强行放大会模糊不清,效果不好 标准化的做法就是需要讲图片的某个部分进行像素扩充
通常是中间的部分抠出来去扩充他不够的地方,这里只需要设置centerrect属性就可以满足了
这样你的size发生变化 ,精灵四周不会变化
对于一个需要角色帧动画的实现使用纹理图册来加载会更有效
SKTextureAtlas *atlas=[SKTextureAtlas atlasNamed:@"monster.alas"];
SKTexture *t1=[atlas textureNamed:@"monster"];
SKTexture *t2=[atlas textureNamed:@"monster"];
SKTexture *t3=[atlas textureNamed:@"monster"];
NSArray *a=@[t1,t2,t3];
序列按时动作的使用
SKSpriteNode *hul=[SKSpriteNode spriteNodeWithImageNamed:@"rocket"];
SKAction *hover=[SKAction sequence:@[
[SKAction waitForDuration:0.5],
[SKAction moveToX:25 duration:0.5],
[SKAction waitForDuration:0.5],
[SKAction moveToX:CGRectGetMidX(self.frame) duration:0.5],
//颜色变化
[SKAction colorizeWithColor:[UIColor redColor] colorBlendFactor:0.7 duration:1],
[SKAction waitForDuration:1.0],
[SKAction moveToX:CGRectGetMaxX(self.frame)-hul.frame.size.width/2 duration:0.5],
[SKAction waitForDuration:0.5],
[SKAction colorizeWithColor:[UIColor whiteColor] colorBlendFactor:0.7 duration:0.5],
[SKAction moveToX:CGRectGetMaxX(self.frame)/2 duration:0.5]
]
];
[hul runAction:[SKAction repeatActionForever:hover]];
//为防止多次点击,运行动画不完全,需要将动画移除
SKAction * actionMoveDone = [SKAction removeFromParent];
一个可以同时进行的序列动作
SKAction *move=[SKAction moveByX:600 y:200 duration:2];
SKAction *scale=[SKAction scaleBy:2 duration:1];
SKAction *rotation=[SKAction rotateByAngle:M_1_PI duration:2];
SKAction *scaleog=[SKAction scaleBy:1 duration:1];
[self.player runAction:[SKAction group:@[move,scale,rotation,scaleog]]];
节点树的绘制顺序
场景渲染的标准行为遵循以下一对简单的规则: • 父节点先绘制自身的内容再渲染子节点。 • 子节点以它们在子节点数组中的顺序依次渲染。
每个节点拥有一个zpostion的标记 让父节点知道先绘制渲染哪个节点 使用的节点的深度来确定节点在屏幕上移动的速度。通过增加不同深度的节点,你可以模拟 视差滚动,比如离我们远的东西他看着跑的慢一些,近一些的要快一些
节点树的搜索
[sknode childnodewithname:@“name”];
[sknode enumeratechildnodewithname:@“name” usingblock^{
//将搜索出的节点进行操作
}];
物理表现形式
hul.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:hul.size];
hul.physicsBody.dynamic=YES;
hul.physicsBody.velocity=CGVectorMake(1, 1);//左上角为坐标原点,向右x增加,向下Y越大
mass 属性决定力是如何影响主体,以及当主体参与碰撞时它有多大的动量。

• friction 属性决定了主体表面的粗糙度。它被用来计算一个主体沿其他主体表面移动时产 生的摩擦力。
• linearDamping 和 angularDamping 属性是用来计算主体在世界中移动时的摩擦。例如, 它可能用于模拟空气或水的摩擦。
• restitution 属性决定主体在碰撞过程中保持能多少能量,即它的弹力。 其他的属性被用来决定模拟在主体本身上如何进行:
• dynamic 属性决定该主体是否由物理子系统来模拟。
• affectedByGravity 属性决定模拟是否对主体产生重力。关于物理世界的更多信息,请 参阅“配置物理世界” 。
• allowsRotation 属性决定力是否能对主体传递角速度(angular velocity)
• gravity 属性对模拟中基于体积的主体施加加速度。静态体和 affectedByGravity 属性 设置为 NO 的物理体则不受影响。
• speed 属性决定了模拟的运行速率。
碰撞效果及检测
遵守协议SKPhysicsContactDelegate
static const uint32_t zidancategory=0x1;
static const uint32_t mostercategory=0x2;
static const uint32_t playercategory=0x3;
_player.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:_player.size];
_player.physicsBody.dynamic=NO;
_player.physicsBody.contactTestBitMask=zidancategory;
_player.physicsBody.categoryBitMask=playercategory;
_player.physicsBody.collisionBitMask=0;
moster.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:moster.size];
moster.physicsBody.dynamic=YES;
moster.physicsBody.contactTestBitMask=zidancategory;
moster.physicsBody.categoryBitMask=mostercategory;
moster.physicsBody.collisionBitMask=4;
moster.physicsBody.usesPreciseCollisionDetection=YES;
zidan.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:zidan.size];
zidan.physicsBody.dynamic=NO;
zidan.physicsBody.contactTestBitMask=mostercategory;
zidan.physicsBody.categoryBitMask=zidancategory;
zidan.physicsBody.collisionBitMask=0;
zidan.physicsBody.usesPreciseCollisionDetection=YES;
- (void)didBeginContact:(SKPhysicsContact *)contact
{
SKPhysicsBody *a;
SKPhysicsBody *b;
if (contact.bodyA.categoryBitMask ==playercategory||contact.bodyB.categoryBitMask==playercategory) {
a=contact.bodyA;
b=contact.bodyB;
[self removecontactnode:a.node andmonster:b.node];
//游戏结束负责写这里的逻辑
}
else if(contact.bodyA.categoryBitMask==zidancategory||contact.bodyB.categoryBitMask==zidancategory)
{
a=contact.bodyA;
b=contact.bodyB;
[self removecontactnode:a.node andmonster:b.node];
SKLabelNode *lavb=(SKLabelNode*)[self childNodeWithName:@"score"];
record+=4;
score=[NSString stringWithFormat:@"score:%d分",record];
lavb.text=score;
}
}
物理联合效果
spring
SKPhysicsJointSpring *joint=[SKPhysicsJointSpring jointWithBodyA:rec1.physicsBody bodyB:rec2.physicsBody anchorA:CGPointMake(0.5, 0.5) anchorB:CGPointMake(0.5, 0.5)];
[self.physicsWorld addJoint:joint];
rope pin fixed sliding使用方法类似
在sk中所有的动画,渲染都由skview对象执行
在skview绘制需要的内容,需要通过另一个继承于sknode(不会绘制内容)的对象skscene
skscene的所有内容是通过它来组织的 ,用场景 来描述各种内容 如:主菜单、结束画面、游戏画面等等,通过skview实现 场景的切换或者呈现
sk使用SkView 加载scene
[skView presentScene:scene];
加载过渡动画场景
[self.view presentScene:scene transition:transition ];
scene中重要的方法
-didmovetoview 场景呈现完调用的方法
- didChangeSize: 当场景大小发生改变时调用该方法
- (void)didMoveToView:(SKView *)view 参数view:持有该场景的视图返回值 论述这个方法通常会被子类重写。执行动画循环
- (void)update:(NSTimeInterval)currentTime 参数currentTime:已经过去的时间,保证单调递增返回值 不要直接调用这个方法,它每一帧会被调用一次
- (void)didSimulatePhysics它每一帧会被调用一次。场景子类应该重写这个方法,并执行一些需要的更新这是对场景变化更改最晚的一个方法
在sk中 所有的内容都是以节点树的形式呈现,一切节点都继承与sknode
常用的精灵:
skspritenode 可以用于创建一个带纹理的精灵
对于纹理的理解,现在不是很深,相当于图片,但是它不同一般的图片,这样的精灵能有更多的属性比如精灵可以再次绘制变色或者其他阴影效果
[SKSpriteNode spriteNodeWithImageNamed:@"background"]
sklabelnode 文本节点
skvideonode 视频节点,用法和avfoundation里面的类似
skemitternode 创建渲染粒子的节点(很酷炫)
NSString *path=[[NSBundle mainBundle]pathForResource:@"snow" ofType:@"sks"];
SKEmitterNode *emitternode=[NSKeyedUnarchiver unarchiveObjectWithFile:path] ;
emitternode.particleScaleRange=0.2;
emitternode.particleLifetimeRange=0.3;
emitternode.particleBirthRate=4;
emitternode.particleSpeed=0.4;
//scale 美妙0.1速度减小
emitternode.particleScaleSpeed=-0.1;
//限定 产生多少粒子,它会自动停下来
emitternode.numParticlesToEmit=40;
//使用序列改变粒子的随时间尺度属性;
SKKeyframeSequence *scalesequence=[[SKKeyframeSequence alloc]initWithKeyframeValues:@[@0.2,@0.7,@0.1] times:@[@0.0,@0.5,@0.7]];
emitternode.particleScaleSequence=scalesequence;
各种节点 在添加时有个默认锚点,也就是精灵的左下角(0,0) 横向0-1垂直方向0-1
锚点也就是对精灵的定位在哪里(比如旋转,放大缩小是以精灵那个部位作为基准的)。。。计算各种碰撞检测,添加内容到场景需要注意
添加节点内容到场景 [node add children:anode];
制作可以拉伸的精灵
gameplaynode.centerRect=CGRectMake(12/28, 12/28, 2/28, 2/28);
表示 4个角分别占12 个像素,中间扣出宽度为2像素的矩形2*2像素大小
这个的效果很有用,比如制作一个对话框,内容很多的时候,他的背景图片只有那么大
强行放大会模糊不清,效果不好 标准化的做法就是需要讲图片的某个部分进行像素扩充
通常是中间的部分抠出来去扩充他不够的地方,这里只需要设置centerrect属性就可以满足了
这样你的size发生变化 ,精灵四周不会变化
对于一个需要角色帧动画的实现使用纹理图册来加载会更有效
SKTextureAtlas *atlas=[SKTextureAtlas atlasNamed:@"monster.alas"];
SKTexture *t1=[atlas textureNamed:@"monster"];
SKTexture *t2=[atlas textureNamed:@"monster"];
SKTexture *t3=[atlas textureNamed:@"monster"];
NSArray *a=@[t1,t2,t3];
序列按时动作的使用
SKSpriteNode *hul=[SKSpriteNode spriteNodeWithImageNamed:@"rocket"];
SKAction *hover=[SKAction sequence:@[
[SKAction waitForDuration:0.5],
[SKAction moveToX:25 duration:0.5],
[SKAction waitForDuration:0.5],
[SKAction moveToX:CGRectGetMidX(self.frame) duration:0.5],
//颜色变化
[SKAction colorizeWithColor:[UIColor redColor] colorBlendFactor:0.7 duration:1],
[SKAction waitForDuration:1.0],
[SKAction moveToX:CGRectGetMaxX(self.frame)-hul.frame.size.width/2 duration:0.5],
[SKAction waitForDuration:0.5],
[SKAction colorizeWithColor:[UIColor whiteColor] colorBlendFactor:0.7 duration:0.5],
[SKAction moveToX:CGRectGetMaxX(self.frame)/2 duration:0.5]
]
];
[hul runAction:[SKAction repeatActionForever:hover]];
//为防止多次点击,运行动画不完全,需要将动画移除
SKAction * actionMoveDone = [SKAction removeFromParent];
一个可以同时进行的序列动作
SKAction *move=[SKAction moveByX:600 y:200 duration:2];
SKAction *scale=[SKAction scaleBy:2 duration:1];
SKAction *rotation=[SKAction rotateByAngle:M_1_PI duration:2];
SKAction *scaleog=[SKAction scaleBy:1 duration:1];
[self.player runAction:[SKAction group:@[move,scale,rotation,scaleog]]];
节点树的绘制顺序
场景渲染的标准行为遵循以下一对简单的规则: • 父节点先绘制自身的内容再渲染子节点。 • 子节点以它们在子节点数组中的顺序依次渲染。
每个节点拥有一个zpostion的标记 让父节点知道先绘制渲染哪个节点 使用的节点的深度来确定节点在屏幕上移动的速度。通过增加不同深度的节点,你可以模拟 视差滚动,比如离我们远的东西他看着跑的慢一些,近一些的要快一些
节点树的搜索
[sknode childnodewithname:@“name”];
[sknode enumeratechildnodewithname:@“name” usingblock^{
//将搜索出的节点进行操作
}];
物理表现形式
hul.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:hul.size];
hul.physicsBody.dynamic=YES;
hul.physicsBody.velocity=CGVectorMake(1, 1);//左上角为坐标原点,向右x增加,向下Y越大
mass 属性决定力是如何影响主体,以及当主体参与碰撞时它有多大的动量。

• friction 属性决定了主体表面的粗糙度。它被用来计算一个主体沿其他主体表面移动时产 生的摩擦力。
• linearDamping 和 angularDamping 属性是用来计算主体在世界中移动时的摩擦。例如, 它可能用于模拟空气或水的摩擦。
• restitution 属性决定主体在碰撞过程中保持能多少能量,即它的弹力。 其他的属性被用来决定模拟在主体本身上如何进行:
• dynamic 属性决定该主体是否由物理子系统来模拟。
• affectedByGravity 属性决定模拟是否对主体产生重力。关于物理世界的更多信息,请 参阅“配置物理世界” 。
• allowsRotation 属性决定力是否能对主体传递角速度(angular velocity)
• gravity 属性对模拟中基于体积的主体施加加速度。静态体和 affectedByGravity 属性 设置为 NO 的物理体则不受影响。
• speed 属性决定了模拟的运行速率。
碰撞效果及检测
遵守协议SKPhysicsContactDelegate
static const uint32_t zidancategory=0x1;
static const uint32_t mostercategory=0x2;
static const uint32_t playercategory=0x3;
_player.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:_player.size];
_player.physicsBody.dynamic=NO;
_player.physicsBody.contactTestBitMask=zidancategory;
_player.physicsBody.categoryBitMask=playercategory;
_player.physicsBody.collisionBitMask=0;
moster.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:moster.size];
moster.physicsBody.dynamic=YES;
moster.physicsBody.contactTestBitMask=zidancategory;
moster.physicsBody.categoryBitMask=mostercategory;
moster.physicsBody.collisionBitMask=4;
moster.physicsBody.usesPreciseCollisionDetection=YES;
zidan.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:zidan.size];
zidan.physicsBody.dynamic=NO;
zidan.physicsBody.contactTestBitMask=mostercategory;
zidan.physicsBody.categoryBitMask=zidancategory;
zidan.physicsBody.collisionBitMask=0;
zidan.physicsBody.usesPreciseCollisionDetection=YES;
- (void)didBeginContact:(SKPhysicsContact *)contact
{
SKPhysicsBody *a;
SKPhysicsBody *b;
if (contact.bodyA.categoryBitMask ==playercategory||contact.bodyB.categoryBitMask==playercategory) {
a=contact.bodyA;
b=contact.bodyB;
[self removecontactnode:a.node andmonster:b.node];
//游戏结束负责写这里的逻辑
}
else if(contact.bodyA.categoryBitMask==zidancategory||contact.bodyB.categoryBitMask==zidancategory)
{
a=contact.bodyA;
b=contact.bodyB;
[self removecontactnode:a.node andmonster:b.node];
SKLabelNode *lavb=(SKLabelNode*)[self childNodeWithName:@"score"];
record+=4;
score=[NSString stringWithFormat:@"score:%d分",record];
lavb.text=score;
}
}
物理联合效果
spring
[self addChild:rec1];
[self addChild:rec2];SKPhysicsJointSpring *joint=[SKPhysicsJointSpring jointWithBodyA:rec1.physicsBody bodyB:rec2.physicsBody anchorA:CGPointMake(0.5, 0.5) anchorB:CGPointMake(0.5, 0.5)];
[self.physicsWorld addJoint:joint];
rope pin fixed sliding使用方法类似
切记 添加子节点到physicsworld addjoint 时你的节点必须是在当前的scene中已经成功添加,且各节点的物理形态时创建了的(physicbody)
以后还会学习高级的用法