sprite kit学习总结,以下简称sk
在sk中所有的动画,渲染都由skview对象执行
在skview绘制需要的内容,需要通过另一个继承于sknode(不会绘制内容)的对象skscene
skscene的所有内容是通过它来组织的,用场景来描述各种内容如:主菜单、结束画面、游戏画面等等,通过skview实现 场景的切换或者呈现
sk使用SkView加载scene
加载过渡动画场景
[self.viewpresentScene:scenetransition:transition ];
scene中重要的方法
-didmovetoview场景呈现完调用的方法
- didChangeSize:当场景大小发生改变时调用该方法
- (void)didMoveToView:(SKView *)view参数view:持有该场景的视图返回值论述这个方法通常会被子类重写。执行动画循环
- (void)update:(NSTimeInterval)currentTime参数currentTime:已经过去的时间,保证单调递增返回值不要直接调用这个方法,它每一帧会被调用一次
- (void)didSimulatePhysics它每一帧会被调用一次。场景子类应该重写这个方法,并执行一些需要的更新这是对场景变化更改最晚的一个方法
在sk中所有的内容都是以节点树的形式呈现,一切节点都继承与sknode
常用的精灵:
skspritenode 可以用于创建一个带纹理的精灵
对于纹理的理解,现在不是很深,相当于图片,但是它不同一般的图片,这样的精灵能有更多的属性比如精灵可以再次绘制变色或者其他阴影效果
[SKSpriteNodespriteNodeWithImageNamed:@"background"]
sklabelnode 文本节点
skvideonode 视频节点,用法和avfoundation里面的类似
skemitternode 创建渲染粒子的节点(很酷炫)
NSString*path=[[NSBundlemainBundle]pathForResource:@"snow"ofType:@"sks"];
SKEmitterNode*emitternode=[NSKeyedUnarchiverunarchiveObjectWithFile: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=[[SKKeyframeSequencealloc]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=[SKTextureAtlasatlasNamed:@"monster.alas"];
SKTexture*t1=[atlastextureNamed:@"monster"];
SKTexture*t2=[atlastextureNamed:@"monster"];
SKTexture*t3=[atlastextureNamed:@"monster"];
NSArray*a=@[t1,t2,t3];
序列按时动作的使用
SKSpriteNode*hul=[SKSpriteNodespriteNodeWithImageNamed:@"rocket"];
SKAction*hover=[SKActionsequence:@[
[SKActionwaitForDuration:0.5],
[SKActionmoveToX:25duration:0.5],
[SKActionwaitForDuration:0.5],
[SKActionmoveToX:CGRectGetMidX(self.frame)duration:0.5],
//颜色变化
[SKActioncolorizeWithColor:[UIColorredColor]colorBlendFactor:0.7duration:1],
[SKActionwaitForDuration:1.0],
[SKActionmoveToX:CGRectGetMaxX(self.frame)-hul.frame.size.width/2duration:0.5],
[SKActionwaitForDuration:0.5],
[SKActioncolorizeWithColor:[UIColorwhiteColor]colorBlendFactor:0.7duration:0.5],
[SKActionmoveToX:CGRectGetMaxX(self.frame)/2duration:0.5]
]
];
[hulrunAction:[SKActionrepeatActionForever:hover]];
//为防止多次点击,运行动画不完全,需要将动画移除
SKAction* actionMoveDone = [SKActionremoveFromParent];
一个可以同时进行的序列动作
SKAction*move=[SKActionmoveByX:600y:200duration:2];
SKAction*scale=[SKActionscaleBy:2duration:1];
SKAction*rotation=[SKActionrotateByAngle:M_1_PIduration:2];
SKAction*scaleog=[SKActionscaleBy:1duration:1];
[self.playerrunAction:[SKActiongroup:@[move,scale,rotation,scaleog]]];
节点树的绘制顺序
场景渲染的标准行为遵循以下一对简单的规则:?父节点先绘制自身的内容再渲染子节点。?子节点以它们在子节点数组中的顺序依次渲染。
每个节点拥有一个zpostion的标记让父节点知道先绘制渲染哪个节点使用的节点的深度来确定节点在屏幕上移动的速度。通过增加不同深度的节点,你可以模拟视差滚动,比如离我们远的东西他看着跑的慢一些,近一些的要快一些
节点树的搜索
[sknode childnodewithname:@“name”];
[sknode enumeratechildnodewithname:@“name” usingblock^{
//将搜索出的节点进行操作
}];
物理表现形式
hul.physicsBody=[SKPhysicsBodybodyWithRectangleOfSize:hul.size];
hul.physicsBody.dynamic=YES;
hul.physicsBody.velocity=CGVectorMake(1,1);//左上角为坐标原点,向右x增加,向下Y越大
mass属性决定力是如何影响主体,以及当主体参与碰撞时它有多大的动量。
page87image17728.png ¬
•friction属性决定了主体表面的粗糙度。它被用来计算一个主体沿其他主体表面移动时产生的摩擦力。
•linearDamping和angularDamping属性是用来计算主体在世界中移动时的摩擦。例如,它可能用于模拟空气或水的摩擦。
•restitution属性决定主体在碰撞过程中保持能多少能量,即它的弹力。其他的属性被用来决定模拟在主体本身上如何进行:
•dynamic属性决定该主体是否由物理子系统来模拟。
•affectedByGravity属性决定模拟是否对主体产生重力。关于物理世界的更多信息,请参阅“配置物理世界”。
•allowsRotation属性决定力是否能对主体传递角速度(angular velocity)
•gravity属性对模拟中基于体积的主体施加加速度。静态体和affectedByGravity属性设置为NO的物理体则不受影响。
•speed属性决定了模拟的运行速率。
碰撞效果及检测
遵守协议SKPhysicsContactDelegate
staticconstuint32_tzidancategory=0x1;
staticconstuint32_tmostercategory=0x2;
staticconstuint32_tplayercategory=0x3;
_player.physicsBody=[SKPhysicsBodybodyWithRectangleOfSize:_player.size];
_player.physicsBody.dynamic=NO;
_player.physicsBody.contactTestBitMask=zidancategory;
_player.physicsBody.categoryBitMask=playercategory;
_player.physicsBody.collisionBitMask=0;
moster.physicsBody=[SKPhysicsBodybodyWithRectangleOfSize:moster.size];
moster.physicsBody.dynamic=YES;
moster.physicsBody.contactTestBitMask=zidancategory;
moster.physicsBody.categoryBitMask=mostercategory;
moster.physicsBody.collisionBitMask=4;
moster.physicsBody.usesPreciseCollisionDetection=YES;
zidan.physicsBody=[SKPhysicsBodybodyWithRectangleOfSize: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;
[selfremovecontactnode:a.nodeandmonster:b.node];
//游戏结束负责写这里的逻辑
}
elseif(contact.bodyA.categoryBitMask==zidancategory||contact.bodyB.categoryBitMask==zidancategory)
{
a=contact.bodyA;
b=contact.bodyB;
[selfremovecontactnode:a.nodeandmonster:b.node];
SKLabelNode*lavb=(SKLabelNode*)[selfchildNodeWithName:@"score"];
record+=4;
score=[NSStringstringWithFormat:@"score:%d分",record];
lavb.text=score;
}
}
物理联合效果
spring
[selfaddChild:rec1];
[selfaddChild:rec2];
SKPhysicsJointSpring*joint=[SKPhysicsJointSpringjointWithBodyA:rec1.physicsBodybodyB:rec2.physicsBodyanchorA:CGPointMake(0.5,0.5)anchorB:CGPointMake(0.5,0.5)];
[self.physicsWorldaddJoint:joint];
rope pin fixed sliding使用方法类似