这是一个用来开发2D游戏的框架。
整个游戏由场景组成,即SKScene的子类。然后让SKView呈现场景,当然在各个场景之间是可以切换的。
在每个场景中都是SpriteKit节点,每个节点都有父节点,也可以有子节点。所有节点的根节点都是SKScene。不同的节点有不同的功能:
- SKSpriteNode 显示一个图像或一个彩色矩形。
- SKLabelNode 显示文字
- SKShapnode 显示任意UIBezierPath
- SKEffectNode 向其所有子节点应用图像特效
- 空的SKNode节点 不会真正显示某些东西,但是用来组织和分类节点是很有效的。
每个场景都会有一个didMoveToView方法,用来执行此场景的初始化工作比较合适。
override func didMoveToView(view: SKView) {
self.scaleMode = .AspectFill
let spritNode = SKSpriteNode(imageNamed: "BlockSquareBlue")
spritNode.position = CGPoint(x: size.width / 2.0, y: size.height / 2.0)
self.addChild(spritNode)
}
节点可以对触碰作出反应
前提是这个节点的userInteractionEnable属性被设置为true,只有SKScene的这个属性是被默认打开的。
override func touchesBegan(touches: Set, withEvent event: UIEvent?) {
let game = GameScene(size: self.size)
let transition = SKTransition.moveInWithDirection(SKTransitionDirection.Right, duration: 0.8)
self.view?.presentScene(game, transition: transition)//这句话就是在场景之间互相切换的语句咯
}
节点可以添加动画
let moveAction = SKAction.moveBy(CGVector(dx: 0, dy: 50), duration: 1.0)
let reversedMovAction = moveAction.reversedAction()
let rotateAction = SKAction.rotateByAngle(CGFloat(M_PI), duration: 2.0)
let reversedrotateAction = rotateAction.reversedAction()
let scaleAction = SKAction.scaleTo(2.0, duration: 0.5)
let reversedscaleAction = scaleAction.reversedAction()
//group里的Action同时开始
let actionGroup = SKAction.group([moveAction,reversedMovAction,rotateAction,reversedrotateAction,scaleAction,reversedscaleAction])
//sequence里的Action顺序执行
let actionSequence = SKAction.sequence([moveAction,reversedMovAction,rotateAction,reversedrotateAction,scaleAction,reversedscaleAction])
//对某个节点应用动作
textLabel.runAction(actionSequence)
节点可以添加特效
要注意,当给节点添加特效时意味着这个节点将成为对应特效节点的子节点。如果这个节点同时是其他节点的子节点会报错,记得先解绑。
//对节点添加特效
let blurFiler = CIFilter(name: "CIGaussianBlur")
blurFiler?.setDefaults()
blurFiler?.setValue(5.0, forKey: "inputRadius")
blurEffectNode.filter = blurFiler
blurEffectNode.shouldEnableEffects = false
self.addChild(blurEffectNode)
//与其他节点不同的是,这里需要将要应用特效的节点加到SKEffectNode节点中
blurEffectNode.addChild(textLabel)
为节点添加物理特效
这里碰到个问题,上文中的SKShapNode并不和边界发生碰撞
//设置物理实体形状,不一定和原来节点形状相同,可能的情况下越简单越好,便于系统计算碰撞效果
let body = SKPhysicsBody(rectangleOfSize: spritNode.frame.size)
spritNode.physicsBody = body
//设置质量kg单位
body.mass = 1.0
//为添加边界实体用SKPhysicsBody(edgeLoopFromRect:)方法创建的实体不受重力影响
let wallsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody = wallsBody
//self.view?.showsPhysics = true//这样可以打开物理调试模式
可以对物理实体进行互相间的接合
有许多种接合的方式
- SKPhysicsJointFixed 两个实体固定,不能相对移动,可以捆绑在一起移动
- SKPhysicsJointSpring 可以相对移动,但是距离越大,将它们拉在一起的力越大
- SKPhysicsJointSliding 可以相对移动,但只能沿一个轴
- SKPhysicsJointPin 一个对象被订到另一个对象上,可以旋转,不能移动。
//创建一个对象接合,接合有很多种SKPhysicsJointSpring是其中一种
let pinJoint = SKPhysicsJointSpring.jointWithBodyA(textbody, bodyB: planebody, anchorA: CGPointMake(textLabel.position.x-100, textLabel.position.y+100), anchorB: planeNode.position)
self.physicsWorld.addJoint(pinJoint)
添加场景照明
let light = SKLightNode()
light.enabled = true
light.lightColor = UIColor.yellowColor()
light.categoryBitMask = 0xFFFFFFFF//场景照明通过掩码来设置哪些元素会被照亮
light.position = lightNode.position
self.addChild(light)
planeNode.lightingBitMask = 0x1//0xFFFFFFFF与0x1与得到了true则这个节点会被照亮
使用自定义着色器:
自定义着色器是完全自定义一个节点最终显示效果的东西。编写着色器需要一个.fsh文件,在这之中编写GLSL(OpenGL Shading Language)来定义最后需要返回的最终效果。
.fsh代码长得像这个样子:
CustomShader.fsh
void main(){
vec4 color = SKDefaultShading();
vec4 noiseSample = texture2D(noiseTexture,v_tex_coord);
if (noiseSample.a < threshold) {
color.a = 0.0;
}
color.rgb *= color.a;
gl_FragColor = color;
}
在使用这个着色器的节点的场景的didMoveToView中可以传给着色器一些参数和配置:
//自定义着色器
let noiseTexture = SKTexture(noiseWithSmoothness: 0.5, size: CGSize(width: 265, height: 256), grayscale: true)
let textureUniform = SKUniform(name: "noiseTexture", texture: noiseTexture)
let thresholdUniform = SKUniform(name: "threshold", float: 0.5)
let shader = SKShader(fileNamed: "CustomShader")
shader.addUniform(textureUniform)
shader.addUniform(thresholdUniform)
imageNode.shader = shader
通过可视化方式来编辑场景
通过Resource文件夹来新建一个SpriteKit场景文件,并建一个名字相同的类,使用MyScene(fileNamed: "MyScene")方法来初始化这个场景,当跳到这个场景的时候就可以显示你在可视化界面创建的场景和动画。当然在这个场景的didMoveToView里你同样可以继续编辑你的代码来进行继续编辑。