How to Clone Flappy Bird in Swift

109
How To Clone FlappyBird in Swift

description

 

Transcript of How to Clone Flappy Bird in Swift

Page 1: How to Clone Flappy Bird in Swift

How To Clone

FlappyBirdin

Swift

Page 2: How to Clone Flappy Bird in Swift

A little introduction

Page 3: How to Clone Flappy Bird in Swift

Who Am I?@giordanoscalzohttps://github.com/gscalzo

Page 4: How to Clone Flappy Bird in Swift

Who Am I?@giordanoscalzohttps://github.com/gscalzo

A developer

Page 5: How to Clone Flappy Bird in Swift

Who Am I?@giordanoscalzohttps://github.com/gscalzo

An iOS developer

Page 6: How to Clone Flappy Bird in Swift

Who Am I?@giordanoscalzohttps://github.com/gscalzo

A Swift beginner

Page 7: How to Clone Flappy Bird in Swift
Page 8: How to Clone Flappy Bird in Swift
Page 9: How to Clone Flappy Bird in Swift

How to implement Hello World in Swift?

Page 10: How to Clone Flappy Bird in Swift

println("Hello, World!")

Page 11: How to Clone Flappy Bird in Swift

println("Hello, World!")

Not exciting :-(

Page 12: How to Clone Flappy Bird in Swift
Page 13: How to Clone Flappy Bird in Swift
Page 14: How to Clone Flappy Bird in Swift

far to be perfect

Page 15: How to Clone Flappy Bird in Swift

but it was fun

Page 16: How to Clone Flappy Bird in Swift

instructions

Page 17: How to Clone Flappy Bird in Swift

git clonehttp://github.com/gscalzo/FlappySwift.git

Page 18: How to Clone Flappy Bird in Swift

./setup

Page 19: How to Clone Flappy Bird in Swift

./setup 1

./setup 2

./setup 3...

Page 20: How to Clone Flappy Bird in Swift
Page 21: How to Clone Flappy Bird in Swift

walking skeleton./setup 1

Page 22: How to Clone Flappy Bird in Swift
Page 23: How to Clone Flappy Bird in Swift

class GameScene: SKScene { private var screenNode: SKSpriteNode!

override func didMoveToView(view: SKView) { // ... }

Page 24: How to Clone Flappy Bird in Swift

override func didMoveToView(view: SKView) { screenNode = SKSpriteNode(color: UIColor.clearColor(), size: self.size) addChild(screenNode)

let backgroundNode = SKSpriteNode(imageNamed: "background") backgroundNode.anchorPoint = CGPointZero backgroundNode.position = CGPointZero screenNode.addChild(backgroundNode)

let groundNode = SKSpriteNode(imageNamed: "ground") groundNode.anchorPoint = CGPointZero groundNode.position = CGPointZero screenNode.addChild(groundNode)}

Page 25: How to Clone Flappy Bird in Swift
Page 26: How to Clone Flappy Bird in Swift

parallax layers./setup 2

Page 27: How to Clone Flappy Bird in Swift

override func didMoveToView(view: SKView) { //... Background(textureNamed: "background").addTo(screenNode).start() Ground(textureNamed: "ground").addTo(screenNode).start()}

Page 28: How to Clone Flappy Bird in Swift

protocol Startable { func start() -> Startable func stop() -> Startable}

Page 29: How to Clone Flappy Bird in Swift

class Background { private var parallaxNode: ParallaxNode! private let textureName: String

init(textureNamed textureName: String) { }

func addTo(parentNode: SKSpriteNode!) -> Background { return self }}

Page 30: How to Clone Flappy Bird in Swift

init(textureNamed textureName: String) { self.textureName = textureName}

func addTo(parentNode: SKSpriteNode!) -> Background { let width = parentNode.size.width let height = parentNode.size.height

parallaxNode = ParallaxNode(width: width, height: height, textureNamed: textureName).addTo(parentNode)

return self}

Page 31: How to Clone Flappy Bird in Swift

extension Background : Startable { func start() -> Startable { parallaxNode.start(duration: 20.0) return self }

func stop() -> Startable { parallaxNode.stop() return self }}

Page 32: How to Clone Flappy Bird in Swift

class Ground { private var parallaxNode: ParallaxNode! private let textureName: String

init(textureNamed textureName: String) { }

func addTo(parentNode: SKSpriteNode!) -> Ground { return self }}

Page 33: How to Clone Flappy Bird in Swift

init(textureNamed textureName: String) { self.textureName = textureName}

func addTo(parentNode: SKSpriteNode!) -> Ground { let width = parentNode.size.width let height = CGFloat(60.0)

parallaxNode = ParallaxNode(width: width, height: height, textureNamed: textureName).zPosition(5).addTo(parentNode) return self}

Page 34: How to Clone Flappy Bird in Swift

extension Ground : Startable { func start() -> Startable { parallaxNode.start(duration: 5.0) return self }

func stop() -> Startable { parallaxNode.stop() return self }}

Page 35: How to Clone Flappy Bird in Swift

How to implement ParallaxNode?

Page 36: How to Clone Flappy Bird in Swift
Page 37: How to Clone Flappy Bird in Swift
Page 38: How to Clone Flappy Bird in Swift
Page 39: How to Clone Flappy Bird in Swift

class ParallaxNode { private let node: SKSpriteNode!

init(width: CGFloat, height: CGFloat, textureNamed: String) { }

private func createNode(textureNamed: String, x: CGFloat) -> SKNode { }

func zPosition(zPosition: CGFloat) -> ParallaxNode { }

func addTo(parentNode: SKSpriteNode) -> ParallaxNode { }

func start(#duration: NSTimeInterval) { }

func stop() { }}

Page 40: How to Clone Flappy Bird in Swift

init(width: CGFloat, height: CGFloat, textureNamed: String) { let size = CGSizeMake(2*width, height) node = SKSpriteNode(color: UIColor.whiteColor(), size: size) node.anchorPoint = CGPointZero node.position = CGPointZero node.addChild(createNode(textureNamed, x: 0)) node.addChild(createNode(textureNamed, x: width))}

Page 41: How to Clone Flappy Bird in Swift

private func createNode(textureNamed: String, x: CGFloat) -> SKNode { let node = SKSpriteNode(imageNamed: textureNamed, normalMapped: true) node.anchorPoint = CGPointZero node.position = CGPoint(x: x, y: 0) return node}

Page 42: How to Clone Flappy Bird in Swift

func zPosition(zPosition: CGFloat) -> ParallaxNode { node.zPosition = zPosition return self}

func addTo(parentNode: SKSpriteNode) -> ParallaxNode { parentNode.addChild(node) return self}

func stop() { node.removeAllActions()}

Page 43: How to Clone Flappy Bird in Swift

func start(#duration: NSTimeInterval) { node.runAction(SKAction.repeatActionForever(SKAction.sequence( [ SKAction.moveToX(-node.size.width/2.0, duration: duration), SKAction.moveToX(0, duration: 0) ] )))}

Page 44: How to Clone Flappy Bird in Swift
Page 45: How to Clone Flappy Bird in Swift

Our hero./setup 3

Page 46: How to Clone Flappy Bird in Swift

override func didMoveToView(view: SKView) { physicsWorld.gravity = CGVector(dx: 0, dy: -3) //... bird = Bird(textureNames: ["bird1", "bird2"]).addTo(screenNode) bird.position = CGPointMake(30.0, 400.0) bird.start()}

Page 47: How to Clone Flappy Bird in Swift

class Bird { private let node: SKSpriteNode! private let textureNames: [String]

var position : CGPoint { set { node.position = newValue } get { return node.position } }

init(textureNames: [String]) { self.textureNames = textureNames node = createNode() }

func addTo(scene: SKSpriteNode) -> Bird{ scene.addChild(node) return self }}

Page 48: How to Clone Flappy Bird in Swift

extension Bird { private func createNode() -> SKSpriteNode { let birdNode = SKSpriteNode(imageNamed: textureNames.first!) birdNode.setScale(1.8) birdNode.zPosition = 2.0

birdNode.physicsBody = SKPhysicsBody(rectangleOfSize: birdNode.size) birdNode.physicsBody!.dynamic = true

return birdNode }}

Page 49: How to Clone Flappy Bird in Swift

extension Bird : Startable { func start() -> Startable { animate() return self }

func stop() -> Startable { node.physicsBody!.dynamic = false node.removeAllActions() return self }}

Page 50: How to Clone Flappy Bird in Swift

private func animate(){ let animationFrames = textureNames.map { texName in SKTexture(imageNamed: texName) }

node.runAction( SKAction.repeatActionForever( SKAction.animateWithTextures(animationFrames, timePerFrame: 0.1) ))}

Page 51: How to Clone Flappy Bird in Swift

func update() { switch node.physicsBody!.velocity.dy { case let dy where dy > 30.0: node.zRotation = (3.14/6.0) case let dy where dy < -100.0: node.zRotation = -1*(3.14/4.0) default: node.zRotation = 0.0 }}

Page 52: How to Clone Flappy Bird in Swift

Bird Physics 101

Page 53: How to Clone Flappy Bird in Swift
Page 54: How to Clone Flappy Bird in Swift

Impulse

Page 55: How to Clone Flappy Bird in Swift
Page 56: How to Clone Flappy Bird in Swift

func flap() { node.physicsBody!.velocity = CGVector(dx: 0, dy: 0) node.physicsBody!.applyImpulse(CGVector(dx: 0, dy: 6))}

Page 57: How to Clone Flappy Bird in Swift
Page 58: How to Clone Flappy Bird in Swift

Pipes!

Page 59: How to Clone Flappy Bird in Swift

Pipes!./setup 4

Page 60: How to Clone Flappy Bird in Swift
Page 61: How to Clone Flappy Bird in Swift

class GameScene: SKScene { override func didMoveToView(view: SKView) { //... Pipes(textureNames: ["pipeTop.png", "pipeBottom.png"]).addTo(screenNode).start() }

Page 62: How to Clone Flappy Bird in Swift

class Pipes { // class let createActionKey = "createActionKey" // class variables not yet supported private class var createActionKey : String { get {return "createActionKey"} }

private var parentNode: SKSpriteNode! private let textureNames: [String]

init(textureNames: [String]) { self.textureNames = textureNames }

func addTo(parentNode: SKSpriteNode) -> Pipes { self.parentNode = parentNode return self }}

Page 63: How to Clone Flappy Bird in Swift

func start() -> Startable { let createAction = SKAction.repeatActionForever( SKAction.sequence( [ SKAction.runBlock { self.createNewPipe() }, SKAction.waitForDuration(3) ] ) )

parentNode.runAction(createAction, withKey: Pipes.createActionKey)

return self}

Page 64: How to Clone Flappy Bird in Swift

func stop() -> Startable { parentNode.removeActionForKey(Pipes.createActionKey)

let pipeNodes = parentNode.children.filter { (node: AnyObject?) -> Bool in (node as SKNode).name == PipePair.kind } for pipe in pipeNodes { pipe.removeAllActions() } return self}

Page 65: How to Clone Flappy Bird in Swift

private func createNewPipe() { PipePair(textures: textureNames, centerY: centerPipes()).addTo(parentNode).start()}

private func centerPipes() -> CGFloat { return parentNode.size.height/2 - 100 + 20 * CGFloat(arc4random_uniform(10))}

Page 66: How to Clone Flappy Bird in Swift

class PipePair { // class let kind = "PIPES" // class variables not yet supported class var kind : String { get {return "PIPES"} }

private let gapSize: CGFloat = 50 private var pipesNode: SKNode! private var finalOffset: CGFloat! private var startingOffset: CGFloat!

Page 67: How to Clone Flappy Bird in Swift

init(textures: [String], centerY: CGFloat){ pipesNode = SKNode() pipesNode.name = PipePair.kind

let pipeTop = createPipe(imageNamed: textures[0]) let pipeTopPosition = CGPoint(x: 0, y: centerY + pipeTop.size.height/2 + gapSize) pipeTop.position = pipeTopPosition pipesNode.addChild(pipeTop)

let pipeBottom = createPipe(imageNamed: textures[1]) let pipeBottomPosition = CGPoint(x: 0 , y: centerY - pipeBottom.size.height/2 - gapSize) pipeBottom.position = pipeBottomPosition pipesNode.addChild(pipeBottom)

let gapNode = createGap(size: CGSize( width: pipeBottom.size.width, height: gapSize*2)) gapNode.position = CGPoint(x: 0, y: centerY) pipesNode.addChild(gapNode)

finalOffset = -pipeBottom.size.width/2 startingOffset = -finalOffset}

Page 68: How to Clone Flappy Bird in Swift

func start() { pipesNode.runAction(SKAction.sequence( [ SKAction.moveToX(finalOffset, duration: 6.0), SKAction.removeFromParent() ] ))}

Page 69: How to Clone Flappy Bird in Swift

private func createPipe(#imageNamed: String) -> SKSpriteNode { let pipeNode = SKSpriteNode(imageNamed: imageNamed) return pipeNode}

private func createGap(#size: CGSize) -> SKSpriteNode { let gapNode = SKSpriteNode(color: UIColor.clearColor(), size: size) return gapNode}

Page 70: How to Clone Flappy Bird in Swift
Page 71: How to Clone Flappy Bird in Swift

Contact./setup 5

Page 72: How to Clone Flappy Bird in Swift

enum BodyType : UInt32 { case bird = 1 // (1 << 0) case ground = 2 // (1 << 1) case pipe = 4 // (1 << 2) case gap = 8 // (1 << 3)}

class GameScene: SKScene {

Page 73: How to Clone Flappy Bird in Swift

extension Bird { private func createNode() -> SKSpriteNode { //... birdNode.physicsBody = SKPhysicsBody(rectangleOfSize: birdNode.size) birdNode.physicsBody?.dynamic = true birdNode.physicsBody?.categoryBitMask = BodyType.bird.toRaw() birdNode.physicsBody?.collisionBitMask = BodyType.bird.toRaw() birdNode.physicsBody?.contactTestBitMask = BodyType.world.toRaw() | BodyType.pipe.toRaw() | BodyType.gap.toRaw()

Page 74: How to Clone Flappy Bird in Swift

Or better, using a builder closure...

extension Bird { private func createNode() -> SKSpriteNode { //... birdNode.physicsBody = SKPhysicsBody.rectSize(birdNode.size) { body in body.dynamic = true body.categoryBitMask = BodyType.bird.toRaw() body.collisionBitMask = BodyType.bird.toRaw() body.contactTestBitMask = BodyType.world.toRaw() | BodyType.pipe.toRaw() | BodyType.gap.toRaw() }

Page 75: How to Clone Flappy Bird in Swift

Handy builder closure extension

extension SKPhysicsBody { typealias BodyBuilderClosure = (SKPhysicsBody) -> ()

class func rectSize(size: CGSize, builderClosure: BodyBuilderClosure) -> SKPhysicsBody { let body = SKPhysicsBody(rectangleOfSize: size) builderClosure(body) return body }}

Page 76: How to Clone Flappy Bird in Swift

class Ground { func addTo(parentNode: SKSpriteNode!) -> Ground { //... groundBody.physicsBody = SKPhysicsBody.rectSize(size) { body in body.dynamic = false body.affectedByGravity = false body.categoryBitMask = BodyType.ground.toRaw() body.collisionBitMask = BodyType.ground.toRaw() }

Page 77: How to Clone Flappy Bird in Swift

extension PipePair { private func createPipe(#imageNamed: String) -> SKSpriteNode { pipeNode.physicsBody = SKPhysicsBody.rectSize(pipeNode.size) { body in body.dynamic = false body.affectedByGravity = false body.categoryBitMask = BodyType.pipe.toRaw() body.collisionBitMask = BodyType.pipe.toRaw() } } private func createGap(#size: CGSize) -> SKSpriteNode { gapNode.physicsBody = SKPhysicsBody.rectSize(size) { body in body.dynamic = false body.affectedByGravity = false body.categoryBitMask = BodyType.gap.toRaw() body.collisionBitMask = BodyType.gap.toRaw() } }}

Page 78: How to Clone Flappy Bird in Swift

extension GameScene: SKPhysicsContactDelegate { func didBeginContact(contact: SKPhysicsContact!) { }

func didEndContact(contact: SKPhysicsContact!) { }}

Page 79: How to Clone Flappy Bird in Swift

func didBeginContact(contact: SKPhysicsContact!) { let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

switch (contactMask) { case BodyType.pipe.toRaw() | BodyType.bird.toRaw(): log("Contact with a pipe") case BodyType.ground.toRaw() | BodyType.bird.toRaw(): log("Contact with ground") default: return }

}

Page 80: How to Clone Flappy Bird in Swift

func didEndContact(contact: SKPhysicsContact!) { let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

switch (contactMask) { case BodyType.gap.toRaw() | BodyType.bird.toRaw(): log("Exit from gap") default: return }}

Page 81: How to Clone Flappy Bird in Swift
Page 82: How to Clone Flappy Bird in Swift

Final touches./setup 6

Page 83: How to Clone Flappy Bird in Swift

class GameScene: SKScene { private var actors: [Startable]! private var score: Score!

Page 84: How to Clone Flappy Bird in Swift

override func didMoveToView(view: SKView) { //... let bg = Background(textureNamed: "background").addTo(screenNode) let gr = Ground(textureNamed: "ground").addTo(screenNode) bird = Bird(textureNames: ["bird1", "bird2"]).addTo(screenNode) bird.position = CGPointMake(30.0, 400.0)

let pi = Pipes(textureNames: ["pipeTop.png", "pipeBottom.png"]).addTo(screenNode) actors = [bg, gr, pi, bird]

score = Score().addTo(screenNode)

for actor in actors { actor.start() }}

Page 85: How to Clone Flappy Bird in Swift

class Score { private var score: SKLabelNode! private var currentScore = 0

func addTo(parentNode: SKSpriteNode) -> Score { score = SKLabelNode(text: "\(currentScore)") score.fontName = "MarkerFelt-Wide" score.fontSize = 30 score.position = CGPoint(x: parentNode.size.width/2, y: parentNode.size.height - 40) parentNode.addChild(score) return self }

func increase() { currentScore += 1 score.text = "\(currentScore)" }}

Page 86: How to Clone Flappy Bird in Swift

func didBeginContact(contact: SKPhysicsContact!) { //... case BodyType.pipe.toRaw() | BodyType.bird.toRaw(): bird.pushDown() case BodyType.ground.toRaw() | BodyType.bird.toRaw(): for actor in actors { actor.stop() }

let shakeAction = SKAction.shake(0.1, amplitudeX: 20) screenNode.runAction(shakeAction)

Page 87: How to Clone Flappy Bird in Swift

func didEndContact(contact: SKPhysicsContact!) { //... case BodyType.gap.toRaw() | BodyType.bird.toRaw(): score.increase()

Page 88: How to Clone Flappy Bird in Swift

extension Bird { func flap() { if !dying { node.physicsBody!.velocity = CGVector(dx: 0, dy: 0) node.physicsBody!.applyImpulse(CGVector(dx: 0, dy: 6)) } }

func pushDown() { dying = true node.physicsBody!.applyImpulse(CGVector(dx: 0, dy: -10)) }

Page 89: How to Clone Flappy Bird in Swift
Page 90: How to Clone Flappy Bird in Swift

Into the Cave./setup 7

Page 91: How to Clone Flappy Bird in Swift

override func didMoveToView(view: SKView) { let textures = Textures.cave() let bg = Background(textureNamed: textures.background).addTo(screenNode) let te = Ground(textureNamed: textures.ground).addTo(screenNode) bird = Bird(textureNames: textures.bird).addTo(screenNode) let pi = Pipes(textureNames: textures.pipes).addTo(screenNode)

Page 92: How to Clone Flappy Bird in Swift

struct Textures { let background: String let ground: String let pipes: [String] let bird: [String]

static func classic() -> Textures { return Textures( background: "background.png", ground: "ground.png", pipes: ["pipeTop.png", "pipeBottom.png"], bird: ["bird1", "bird2"]) }

static func cave() -> Textures { return Textures( background: "cave_background.png", ground: "cave_ground.png", pipes: ["cave_pipeTop.png", "cave_pipeBottom.png"], bird: ["bird1", "bird2"]) }}

Page 93: How to Clone Flappy Bird in Swift

extension Bird { private func addLightEmitter() { let light = SKLightNode() light.categoryBitMask = BodyType.bird.toRaw() light.falloff = 1 light.ambientColor = UIColor.whiteColor() light.lightColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.5) light.shadowColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.5) node.addChild(light) }}

Page 94: How to Clone Flappy Bird in Swift

extension PipePair { private func createPipe(#imageNamed: String) -> SKSpriteNode { let pipeNode = SKSpriteNode(imageNamed: imageNamed) pipeNode.shadowCastBitMask = BodyType.bird.toRaw() pipeNode.physicsBody = SKPhysicsBody.rectSize(pipeNode.size) {

Page 95: How to Clone Flappy Bird in Swift

private func createNode(textureNamed: String, x: CGFloat) -> SKNode { let node = SKSpriteNode(imageNamed: textureNamed, normalMapped: true) node.lightingBitMask = BodyType.bird.toRaw()

Page 96: How to Clone Flappy Bird in Swift

What if

Michael Baywas the designer?

./setup 8

Page 97: How to Clone Flappy Bird in Swift
Page 98: How to Clone Flappy Bird in Swift

Explosions!

Page 99: How to Clone Flappy Bird in Swift

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { switch touches.count { case 1: bird.flap() default: shoot() }}

Page 100: How to Clone Flappy Bird in Swift

extension GameScene { private func shoot(#emitterName: String, finalYPosition: CGFloat) { let fireBoltEmmitter = SKEmitterNode.emitterNodeWithName(emitterName) fireBoltEmmitter.position = bird.position fireBoltEmmitter.physicsBody = SKPhysicsBody.rectSize(CGSize(width: 20, height: 20)) { body in body.dynamic = true body.categoryBitMask = BodyType.bomb.toRaw() body.collisionBitMask = BodyType.bomb.toRaw() body.contactTestBitMask = BodyType.pipe.toRaw() } screenNode.addChild(fireBoltEmmitter)

fireBoltEmmitter.runAction(SKAction.sequence( [ SKAction.moveByX(500, y: 100, duration: 1), SKAction.removeFromParent() ])) }

private func shoot() { shoot(emitterName: "fireBolt", finalYPosition: 1000) }

Page 101: How to Clone Flappy Bird in Swift
Page 102: How to Clone Flappy Bird in Swift

Game menu

Page 103: How to Clone Flappy Bird in Swift

Leaderboard

Page 104: How to Clone Flappy Bird in Swift

Swifterims!

Page 105: How to Clone Flappy Bird in Swift

Please: Fork and PRsgithub.com/gscalzo/FlappySwift

Page 106: How to Clone Flappy Bird in Swift

credits

SKLightNode tutorialhttp://www.ymc.ch/en/playing-with-ios-8-sprite-kit-and-sklightnode

Assets for Cave versionhttp://www.free-pobo.com

Page 107: How to Clone Flappy Bird in Swift

Thank you!

Page 108: How to Clone Flappy Bird in Swift

Questions?

Page 109: How to Clone Flappy Bird in Swift