Created
May 4, 2016 19:23
-
-
Save josephspurrier/60bb9d75dabfb8398396d2a1ae7646c8 to your computer and use it in GitHub Desktop.
Flappy Bird in Swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// GameScene.swift | |
// Flappy Bird | |
// | |
// Created on 4/20/16. | |
// Copyright (c) 2016 Joseph Spurrier. All rights reserved. | |
// | |
import SpriteKit | |
class GameScene: SKScene, SKPhysicsContactDelegate { | |
var score = 0 | |
var scoreLabel = SKLabelNode() | |
var gameoverLabel = SKLabelNode() | |
var bird = SKSpriteNode() | |
var bg = SKSpriteNode() | |
var pipe1 = SKSpriteNode() | |
var pipe2 = SKSpriteNode() | |
var movingObjects = SKSpriteNode() | |
var labelContainer = SKSpriteNode() | |
enum ColliderType: UInt32 { | |
case Bird = 1 | |
case Object = 2 | |
case Gap = 4 | |
} | |
var gameOver = false | |
override func didMoveToView(view: SKView) { | |
/* Setup your scene here */ | |
self.physicsWorld.contactDelegate = self | |
self.addChild(movingObjects) | |
self.addChild(labelContainer) | |
// Bird | |
let birdTexture = SKTexture(imageNamed: "flappy1.png") | |
let birdTexture2 = SKTexture(imageNamed: "flappy2.png") | |
let animation = SKAction.animateWithTextures([birdTexture, birdTexture2], timePerFrame: 0.1) | |
let makeBirdFlap = SKAction.repeatActionForever(animation) | |
bird = SKSpriteNode(texture: birdTexture) | |
bird.physicsBody = SKPhysicsBody(circleOfRadius: birdTexture.size().height/2) | |
bird.physicsBody!.dynamic = true | |
bird.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame)) | |
bird.physicsBody?.allowsRotation = false | |
bird.runAction(makeBirdFlap) | |
bird.physicsBody!.categoryBitMask = ColliderType.Bird.rawValue | |
bird.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue | |
bird.physicsBody!.collisionBitMask = ColliderType.Object.rawValue | |
makeBackground() | |
// Score label | |
scoreLabel.fontName = "Helvetica" | |
scoreLabel.fontSize = 60 | |
scoreLabel.text = "0" | |
scoreLabel.position = CGPointMake(CGRectGetMidX(self.frame), self.frame.size.height - 70) | |
// Positions | |
bird.zPosition = 7 | |
scoreLabel.zPosition = 15 | |
// Add the objects to the screen | |
self.addChild(bird) | |
self.addChild(scoreLabel) | |
_ = NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: #selector(GameScene.makePipes), userInfo: nil, repeats: true) | |
} | |
func makeBackground() { | |
// Ground | |
let ground = SKNode() | |
ground.position = CGPointMake(0, 0) | |
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, 1)) | |
ground.physicsBody!.dynamic = false | |
ground.physicsBody!.categoryBitMask = ColliderType.Object.rawValue | |
ground.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue | |
ground.physicsBody!.collisionBitMask = ColliderType.Object.rawValue | |
// Background(s) | |
let bgTexture = SKTexture(imageNamed: "bg.png") | |
let movebg = SKAction.moveByX(-bgTexture.size().width, y: 0, duration: 9) | |
let replacebg = SKAction.moveByX(bgTexture.size().width, y: 0, duration: 0) | |
let movebgForever = SKAction.repeatActionForever(SKAction.sequence([movebg,replacebg])) | |
for var i: CGFloat = 0; i<3; i++ { | |
bg = SKSpriteNode(texture: bgTexture) | |
bg.position = CGPoint(x: bgTexture.size().width/2 + bgTexture.size().width * i, y: CGRectGetMidY(self.frame)) | |
bg.size.height = self.frame.height | |
bg.runAction(movebgForever) | |
bg.zPosition = 3 | |
movingObjects.addChild(bg) | |
} | |
ground.zPosition = 5 | |
movingObjects.addChild(ground) | |
} | |
func makePipes() { | |
// Pipes | |
let gapHeight = bird.size.height * 4 | |
let movementAmount = arc4random() % UInt32(self.frame.size.height / 2) | |
let pipeOffset = CGFloat(movementAmount) - self.frame.size.height / 4 | |
let movePipes = SKAction.moveByX(-self.frame.size.width * 2, y: 0, duration: NSTimeInterval(self.frame.size.width / 100)) | |
let removePipes = SKAction.removeFromParent() | |
let moveAndRemovePipes = SKAction.sequence([movePipes, removePipes]) | |
let pipeTexture1 = SKTexture(imageNamed: "pipe1.png") | |
pipe1 = SKSpriteNode(texture: pipeTexture1) | |
pipe1.position = CGPoint(x: CGRectGetMidX(self.frame) + self.frame.size.width, y: CGRectGetMidY(self.frame) + pipeTexture1.size().height/2 + gapHeight / 2 + pipeOffset) | |
pipe1.runAction(moveAndRemovePipes) | |
pipe1.physicsBody = SKPhysicsBody(rectangleOfSize: pipeTexture1.size()) | |
pipe1.physicsBody!.categoryBitMask = ColliderType.Object.rawValue | |
pipe1.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue | |
pipe1.physicsBody!.collisionBitMask = ColliderType.Object.rawValue | |
pipe1.physicsBody!.dynamic = false | |
let pipeTexture2 = SKTexture(imageNamed: "pipe2.png") | |
pipe2 = SKSpriteNode(texture: pipeTexture2) | |
pipe2.position = CGPoint(x: CGRectGetMidX(self.frame) + self.frame.size.width, y: CGRectGetMidY(self.frame) - pipeTexture2.size().height/2 - gapHeight / 2 + pipeOffset) | |
pipe2.runAction(moveAndRemovePipes) | |
pipe2.physicsBody = SKPhysicsBody(rectangleOfSize: pipeTexture2.size()) | |
pipe2.physicsBody!.categoryBitMask = ColliderType.Object.rawValue | |
pipe2.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue | |
pipe2.physicsBody!.collisionBitMask = ColliderType.Object.rawValue | |
pipe2.physicsBody!.dynamic = false | |
pipe1.zPosition = 8 | |
pipe2.zPosition = 8 | |
movingObjects.addChild(pipe1) | |
movingObjects.addChild(pipe2) | |
let gap = SKNode() | |
gap.position = CGPoint(x: CGRectGetMidX(self.frame) + self.frame.size.width, y: CGRectGetMidY(self.frame) + pipeOffset) | |
gap.runAction(moveAndRemovePipes) | |
gap.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(pipe1.size.width, gapHeight)) | |
gap.physicsBody!.dynamic = false | |
gap.physicsBody!.categoryBitMask = ColliderType.Gap.rawValue | |
gap.physicsBody!.contactTestBitMask = ColliderType.Bird.rawValue | |
gap.physicsBody!.collisionBitMask = ColliderType.Gap.rawValue | |
movingObjects.addChild(gap) | |
} | |
func didBeginContact(contact: SKPhysicsContact) { | |
if contact.bodyA.categoryBitMask == ColliderType.Gap.rawValue || contact.bodyB.categoryBitMask == ColliderType.Gap.rawValue { | |
score += 1 | |
//print(score) | |
scoreLabel.text = String(score) | |
} else { | |
if gameOver == false { | |
gameOver = true | |
self.speed = 0 | |
gameoverLabel.fontName = "Helvetica" | |
gameoverLabel.fontSize = 30 | |
gameoverLabel.text = "Game Over! Tap to play again." | |
gameoverLabel.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)) | |
gameoverLabel.zPosition = 20 | |
labelContainer.addChild(gameoverLabel) | |
} | |
} | |
} | |
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { | |
/* Called when a touch begins */ | |
if gameOver == false { | |
bird.physicsBody!.velocity = CGVectorMake(0,0) | |
bird.physicsBody!.applyImpulse(CGVectorMake(0, 50)) | |
} else { | |
score = 0 | |
scoreLabel.text = "0" | |
bird.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)) | |
bird.physicsBody?.velocity = CGVectorMake(0, 0) | |
movingObjects.removeAllChildren() | |
makeBackground() | |
labelContainer.removeAllChildren() | |
self.speed = 1 | |
gameOver = false | |
} | |
} | |
override func update(currentTime: CFTimeInterval) { | |
/* Called before each frame is rendered */ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment