├── .DS_Store ├── panda.zip ├── Flappy Bird ├── .DS_Store ├── Flappy Bird │ ├── .DS_Store │ ├── Actions.sks │ ├── Resources │ │ ├── Art.zip │ │ ├── Sounds │ │ │ ├── pop.wav │ │ │ ├── coin.wav │ │ │ ├── ding.wav │ │ │ ├── whack.wav │ │ │ ├── falling.wav │ │ │ ├── flapping.wav │ │ │ └── hitGround.wav │ │ ├── Art │ │ │ ├── sprites.atlas │ │ │ │ ├── OK.png │ │ │ │ ├── Bird0.png │ │ │ │ ├── Bird1.png │ │ │ │ ├── Bird2.png │ │ │ │ ├── Bird3.png │ │ │ │ ├── Logo.png │ │ │ │ ├── OK@2x.png │ │ │ │ ├── Pause.png │ │ │ │ ├── Play.png │ │ │ │ ├── Rate.png │ │ │ │ ├── Ready.png │ │ │ │ ├── Score.png │ │ │ │ ├── Share.png │ │ │ │ ├── Button.png │ │ │ │ ├── Cloud1.png │ │ │ │ ├── Cloud2.png │ │ │ │ ├── Cloud3.png │ │ │ │ ├── Ground.png │ │ │ │ ├── Logo@2x.png │ │ │ │ ├── Play@2x.png │ │ │ │ ├── Rate@2x.png │ │ │ │ ├── Bird0@2x.png │ │ │ │ ├── Bird1@2x.png │ │ │ │ ├── Bird2@2x.png │ │ │ │ ├── Bird3@2x.png │ │ │ │ ├── Button@2x.png │ │ │ │ ├── CactusTop.png │ │ │ │ ├── Cloud1@2x.png │ │ │ │ ├── Cloud2@2x.png │ │ │ │ ├── Cloud3@2x.png │ │ │ │ ├── GameOver.png │ │ │ │ ├── Ground@2x.png │ │ │ │ ├── Pause@2x.png │ │ │ │ ├── Ready@2x.png │ │ │ │ ├── Score@2x.png │ │ │ │ ├── Scorecard.png │ │ │ │ ├── Share@2x.png │ │ │ │ ├── Sombrero.png │ │ │ │ ├── ButtonRight.png │ │ │ │ ├── ButtonSquare.png │ │ │ │ ├── CactusBottom.png │ │ │ │ ├── CactusTop@2x.png │ │ │ │ ├── GameOver@2x.png │ │ │ │ ├── Scorecard@2x.png │ │ │ │ ├── Sombrero@2x.png │ │ │ │ ├── button_learn.png │ │ │ │ ├── ButtonRight@2x.png │ │ │ │ ├── ButtonSquare@2x.png │ │ │ │ ├── CactusBottom@2x.png │ │ │ │ └── button_learn@2x.png │ │ │ └── backgrounds.atlas │ │ │ │ ├── Tutorial.png │ │ │ │ ├── Background.png │ │ │ │ ├── Tutorial@2x.png │ │ │ │ └── Background@2x.png │ │ └── SKTUtils │ │ │ ├── SKColor+Extensions.swift │ │ │ ├── SKAction+Extensions.swift │ │ │ ├── Int+Extensions.swift │ │ │ ├── Vector3.swift │ │ │ ├── SKTAudio.swift │ │ │ ├── CGFloat+Extensions.swift │ │ │ ├── SKNode+Extensions.swift │ │ │ ├── SKAction+SpecialEffects.swift │ │ │ ├── SKTEffects.swift │ │ │ ├── CGVector+Extensions.swift │ │ │ ├── CGPoint+Extensions.swift │ │ │ └── SKTTimingFunctions.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── icon_120.png │ │ │ ├── icon_180.png │ │ │ └── Contents.json │ │ └── Spaceship.imageset │ │ │ ├── Spaceship.png │ │ │ └── Contents.json │ ├── Class │ │ ├── MGBird.swift │ │ └── BitMaskType.swift │ ├── Info.plist │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── GameViewController.swift │ ├── AppDelegate.swift │ └── GameScene.swift └── Flappy Bird.xcodeproj │ ├── xcuserdata │ └── ZBKF001.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── Flappy Bird.xcscheme │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── ZBKF001.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── project.pbxproj └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/.DS_Store -------------------------------------------------------------------------------- /panda.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/panda.zip -------------------------------------------------------------------------------- /Flappy Bird/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/.DS_Store -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/.DS_Store -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Actions.sks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Actions.sks -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art.zip -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Sounds/pop.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Sounds/pop.wav -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Sounds/coin.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Sounds/coin.wav -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Sounds/ding.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Sounds/ding.wav -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Sounds/whack.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Sounds/whack.wav -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Sounds/falling.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Sounds/falling.wav -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Sounds/flapping.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Sounds/flapping.wav -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Sounds/hitGround.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Sounds/hitGround.wav -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/OK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/OK.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird0.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird1.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird2.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird3.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Logo.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/OK@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/OK@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Pause.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Play.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Rate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Rate.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Ready.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Ready.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Score.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Score.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Share.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Button.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Cloud1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Cloud1.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Cloud2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Cloud2.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Cloud3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Cloud3.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Ground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Ground.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Logo@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Play@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Play@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Rate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Rate@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird0@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird1@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird2@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird3@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Bird3@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Button@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Button@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/CactusTop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/CactusTop.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Cloud1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Cloud1@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Cloud2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Cloud2@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Cloud3@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Cloud3@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/GameOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/GameOver.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Ground@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Ground@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Pause@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Pause@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Ready@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Ready@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Score@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Score@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Scorecard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Scorecard.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Share@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Share@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Sombrero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Sombrero.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/backgrounds.atlas/Tutorial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/backgrounds.atlas/Tutorial.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/ButtonRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/ButtonRight.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/ButtonSquare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/ButtonSquare.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/CactusBottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/CactusBottom.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/CactusTop@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/CactusTop@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/GameOver@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/GameOver@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Scorecard@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Scorecard@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Sombrero@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/Sombrero@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/button_learn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/button_learn.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Assets.xcassets/AppIcon.appiconset/icon_120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Assets.xcassets/AppIcon.appiconset/icon_120.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Assets.xcassets/AppIcon.appiconset/icon_180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Assets.xcassets/AppIcon.appiconset/icon_180.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/backgrounds.atlas/Background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/backgrounds.atlas/Background.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/backgrounds.atlas/Tutorial@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/backgrounds.atlas/Tutorial@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/ButtonRight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/ButtonRight@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/ButtonSquare@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/ButtonSquare@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/CactusBottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/CactusBottom@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/button_learn@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/sprites.atlas/button_learn@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Assets.xcassets/Spaceship.imageset/Spaceship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Assets.xcassets/Spaceship.imageset/Spaceship.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/Art/backgrounds.atlas/Background@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird/Resources/Art/backgrounds.atlas/Background@2x.png -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird.xcodeproj/xcuserdata/ZBKF001.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird.xcodeproj/project.xcworkspace/xcuserdata/ZBKF001.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LYM-mg/MGFlappy-Bird/HEAD/Flappy Bird/Flappy Bird.xcodeproj/project.xcworkspace/xcuserdata/ZBKF001.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Assets.xcassets/Spaceship.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "Spaceship.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Class/MGBird.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MGBird.swift 3 | // Flappy Bird 4 | // 5 | // Created by i-Techsys.com on 16/12/22. 6 | // Copyright © 2016年 i-Techsys. All rights reserved. 7 | // SKSpriteNode(imageNamed: "Bird0") 8 | 9 | import SpriteKit 10 | 11 | //class MGBird: SKSpriteNode { 12 | // init() { 13 | // super.init(texture: <#T##SKTexture?#>, size: <#T##CGSize#>) 14 | // } 15 | // 16 | // required init?(coder aDecoder: NSCoder) { 17 | // fatalError("init(coder:) has not been implemented") 18 | // } 19 | //} 20 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird.xcodeproj/xcuserdata/ZBKF001.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Flappy Bird.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | C0F7BFF01DFC128600948E16 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Class/BitMaskType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BitMaskType.swift 3 | // Flappy Bird 4 | // 5 | // Created by i-Techsys.com on 16/12/12. 6 | // Copyright © 2016年 i-Techsys. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct 物理层 { 12 | static let 无: UInt32 = 0 13 | static let 游戏角色: UInt32 = 0b1 // 1 14 | static let 障碍物: UInt32 = 0b10 // 2 15 | static let 地面: UInt32 = 0b100 // 4 16 | } 17 | 18 | enum 图层: CGFloat { 19 | case 背景 20 | case 障碍物 21 | case 前景 22 | case 游戏角色 23 | case UI 24 | } 25 | 26 | enum 游戏状态 { 27 | case 主菜单 28 | case 教程 29 | case 游戏 30 | case 跌落 31 | case 显示分数 32 | case 结束🔚 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MGFlappy-Bird 2 | 飞翔的小鸟 3 | 4 | # 一、愤怒的小鸟 5 | # - 去下载源码和去AppStore评价APP 6 | ![去下载源码和去AppStore评价APP.gif](http://upload-images.jianshu.io/upload_images/1429890-407c9bc0b493142d.gif?imageMogr2/auto-orient/strip) 7 | 8 | # - 开始游戏 9 | ![开始游戏.gif](http://upload-images.jianshu.io/upload_images/1429890-769bd27007f6e80f.gif?imageMogr2/auto-orient/strip) 10 | 11 | # - 换肤(只需要解压项目的文件夹Art替换即可) 12 | ![](http://upload-images.jianshu.io/upload_images/1429890-4fdbb1b2f47a4b77.gif?imageMogr2/auto-orient/strip) 13 | ![换肤.png](http://upload-images.jianshu.io/upload_images/1429890-ef6c18dbf976e207.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 14 | *** 15 | 16 | # 二、panda 17 |  - ![panda.gif](http://upload-images.jianshu.io/upload_images/1429890-fb4c72e42fc4ce58.gif?imageMogr2/auto-orient/strip) 18 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "icon_120.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "icon_180.png", 43 | "scale" : "3x" 44 | } 45 | ], 46 | "info" : { 47 | "version" : 1, 48 | "author" : "xcode" 49 | } 50 | } -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UIStatusBarHidden 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/SKTUtils/SKColor+Extensions.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import SpriteKit 24 | 25 | public func SKColorWithRGB(r: Int, g: Int, b: Int) -> SKColor { 26 | return SKColor(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0, blue: CGFloat(b)/255.0, alpha: 1.0) 27 | } 28 | 29 | public func SKColorWithRGBA(r: Int, g: Int, b: Int, a: Int) -> SKColor { 30 | return SKColor(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0, blue: CGFloat(b)/255.0, alpha: CGFloat(a)/255.0) 31 | } 32 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/GameViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameViewController.swift 3 | // Flappy Bird 4 | // 5 | // Created by i-Techsys.com on 16/12/10. 6 | // Copyright © 2016年 i-Techsys. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SpriteKit 11 | import GameplayKit 12 | 13 | 14 | class GameViewController: UIViewController { 15 | override func viewWillLayoutSubviews() { 16 | super.viewWillLayoutSubviews() 17 | 18 | if let sk视图 = self.view as? SKView { 19 | if sk视图.scene == nil { 20 | // 创建场景 21 | let 长宽比 = sk视图.bounds.size.height / sk视图.bounds.size.width 22 | let 场景 = GameScene(size:CGSize(width: 320, height: 320 * 长宽比)) 23 | sk视图.showsFPS = true 24 | sk视图.showsNodeCount = true 25 | sk视图.showsPhysics = true 26 | sk视图.ignoresSiblingOrder = true 27 | 28 | 场景.scaleMode = .aspectFill 29 | 30 | sk视图.presentScene(场景) 31 | } 32 | } 33 | } 34 | 35 | } 36 | 37 | //class GameViewController: UIViewController { 38 | // 39 | // override func viewDidLoad() { 40 | // super.viewDidLoad() 41 | // 42 | // if let view = self.view as! SKView? { 43 | // if let scene = SKScene(fileNamed: "GameScene") { 44 | // scene.scaleMode = .aspectFill 45 | // view.presentScene(scene) 46 | // } 47 | // 48 | // view.ignoresSiblingOrder = true 49 | // view.showsFPS = true 50 | // view.showsNodeCount = true 51 | // view.ignoresSiblingOrder = true 52 | // } 53 | // } 54 | // 55 | // override func didReceiveMemoryWarning() { 56 | // super.didReceiveMemoryWarning() 57 | // // Release any cached data, images, etc that aren't in use. 58 | // } 59 | // 60 | // override var prefersStatusBarHidden: Bool { 61 | // return true 62 | // } 63 | //} 64 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Flappy Bird 4 | // 5 | // Created by i-Techsys.com on 16/12/10. 6 | // Copyright © 2016年 i-Techsys. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/SKTUtils/SKAction+Extensions.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import SpriteKit 24 | 25 | public extension SKAction { 26 | /** 27 | * Performs an action after the specified delay. 28 | */ 29 | public class func afterDelay(delay: TimeInterval, performAction action: SKAction) -> SKAction { 30 | return SKAction.sequence([SKAction.wait(forDuration: delay), action]) 31 | } 32 | 33 | /** 34 | * Performs a block after the specified delay. dispatch_block_t 35 | */ 36 | public class func afterDelay(delay: TimeInterval, runBlock block:@escaping (() -> ())) -> SKAction { 37 | return SKAction.afterDelay(delay: delay, performAction: SKAction.run(block)) 38 | } 39 | 40 | /** 41 | * Removes the node from its parent after the specified delay. 42 | */ 43 | public class func removeFromParentAfterDelay(delay: TimeInterval) -> SKAction { 44 | return SKAction.afterDelay(delay: delay, performAction: SKAction.removeFromParent()) 45 | } 46 | 47 | /** 48 | * Creates an action to perform a parabolic jump. 49 | */ 50 | public class func jumpToHeight(height: CGFloat, duration: TimeInterval, originalPosition: CGPoint) -> SKAction { 51 | return SKAction.customAction(withDuration: duration) {(node, elapsedTime) in 52 | let fraction = elapsedTime / CGFloat(duration) 53 | let yOffset = height * 4 * fraction * (1 - fraction) 54 | node.position = CGPoint(x: originalPosition.x, y: originalPosition.y + yOffset) 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/SKTUtils/Int+Extensions.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import CoreGraphics 24 | 25 | public extension Int { 26 | /** 27 | * Ensures that the integer value stays with the specified range. 28 | */ 29 | public func clamped(range: Range) -> Int { 30 | return (self < range.lowerBound) ? range.lowerBound : ((self >= range.upperBound) ? range.upperBound - 1: self) 31 | } 32 | 33 | /** 34 | * Ensures that the integer value stays with the specified range. 35 | */ 36 | public mutating func clamp(range: Range) -> Int { 37 | self = clamped(range: range) 38 | return self 39 | } 40 | 41 | /** 42 | * Ensures that the integer value stays between the given values, inclusive. 43 | */ 44 | public func clamped(v1: Int, _ v2: Int) -> Int { 45 | let min = v1 < v2 ? v1 : v2 46 | let max = v1 > v2 ? v1 : v2 47 | return self < min ? min : (self > max ? max : self) 48 | } 49 | 50 | /** 51 | * Ensures that the integer value stays between the given values, inclusive. 52 | */ 53 | public mutating func clamp(v1: Int, _ v2: Int) -> Int { 54 | self = clamped(v1: v1, v2) 55 | return self 56 | } 57 | 58 | /** 59 | * Returns a random integer in the specified range. 60 | */ 61 | public static func random(range: Range) -> Int { 62 | return Int(arc4random_uniform(UInt32(range.upperBound - range.lowerBound))) + range.lowerBound 63 | } 64 | 65 | /** 66 | * Returns a random integer between 0 and n-1. 67 | */ 68 | public static func random(n: Int) -> Int { 69 | return Int(arc4random_uniform(UInt32(n))) 70 | } 71 | 72 | /** 73 | * Returns a random integer in the range min...max, inclusive. 74 | */ 75 | public static func random(_ min: Int, max: Int) -> Int { 76 | assert(min < max) 77 | return Int(arc4random_uniform(UInt32(max - min + 1))) + min 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/SKTUtils/Vector3.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import CoreGraphics 24 | 25 | public struct Vector3: Equatable { 26 | var x: CGFloat 27 | var y: CGFloat 28 | var z: CGFloat 29 | 30 | public init(x: CGFloat, y: CGFloat, z: CGFloat) { 31 | self.x = x 32 | self.y = y 33 | self.z = z 34 | } 35 | } 36 | 37 | public func == (lhs: Vector3, rhs: Vector3) -> Bool { 38 | return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z 39 | } 40 | 41 | extension Vector3 { 42 | /** 43 | * Returns true if all the vector elements are equal to the provided value. 44 | */ 45 | public func equalToScalar(value: CGFloat) -> Bool { 46 | return x == value && y == value && z == value 47 | } 48 | 49 | /** 50 | * Returns the magnitude of the vector. 51 | **/ 52 | public func length() -> CGFloat { 53 | return sqrt(x*x + y*y + z*z) 54 | } 55 | 56 | /** 57 | * Normalizes the vector and returns the result as a new vector. 58 | */ 59 | public func normalized() -> Vector3 { 60 | let scale = 1.0/length() 61 | return Vector3(x: x * scale, y: y * scale, z: z * scale) 62 | } 63 | 64 | /** 65 | * Normalizes the vector described by this Vector3 object. 66 | */ 67 | public mutating func normalize() { 68 | let scale = 1.0/length() 69 | x *= scale 70 | y *= scale 71 | z *= scale 72 | } 73 | 74 | /** 75 | * Calculates the dot product of two vectors. 76 | */ 77 | public static func dotProduct(left: Vector3, right: Vector3) -> CGFloat { 78 | return left.x * right.x + left.y * right.y + left.z * right.z 79 | } 80 | 81 | /** 82 | * Calculates the cross product of two vectors. 83 | */ 84 | public static func crossProduct(left: Vector3, right: Vector3) -> Vector3 { 85 | let crossProduct = Vector3(x: left.y * right.z - left.z * right.y, 86 | y: left.z * right.x - left.x * right.z, 87 | z: left.x * right.y - left.y * right.x) 88 | return crossProduct 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/SKTUtils/SKTAudio.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import AVFoundation 24 | 25 | /** 26 | * Audio player that uses AVFoundation to play looping background music and 27 | * short sound effects. For when using SKActions just isn't good enough. 28 | */ 29 | public class SKTAudio { 30 | public var backgroundMusicPlayer: AVAudioPlayer? 31 | public var soundEffectPlayer: AVAudioPlayer? 32 | 33 | public class func sharedInstance() -> SKTAudio { 34 | return SKTAudioInstance 35 | } 36 | 37 | public func playBackgroundMusic(filename: String) { 38 | let url = Bundle.main.url(forResource: filename, withExtension: nil) 39 | if (url == nil) { 40 | print("Could not find file: \(filename)") 41 | return 42 | } 43 | 44 | var error: NSError? = nil 45 | do { 46 | backgroundMusicPlayer = try AVAudioPlayer(contentsOf: url!) 47 | } catch let error1 as NSError { 48 | error = error1 49 | backgroundMusicPlayer = nil 50 | } 51 | if let player = backgroundMusicPlayer { 52 | player.numberOfLoops = -1 53 | player.prepareToPlay() 54 | player.play() 55 | } else { 56 | print("Could not create audio player: \(error!)") 57 | } 58 | } 59 | 60 | public func pauseBackgroundMusic() { 61 | if let player = backgroundMusicPlayer { 62 | if player.isPlaying { 63 | player.pause() 64 | } 65 | } 66 | } 67 | 68 | public func resumeBackgroundMusic() { 69 | if let player = backgroundMusicPlayer { 70 | if !player.isPlaying { 71 | player.play() 72 | } 73 | } 74 | } 75 | 76 | public func playSoundEffect(filename: String) { 77 | let url = Bundle.main.url(forResource: filename, withExtension: nil) 78 | if (url == nil) { 79 | print("Could not find file: \(filename)") 80 | return 81 | } 82 | 83 | var error: NSError? = nil 84 | do { 85 | soundEffectPlayer = try AVAudioPlayer(contentsOf: url!) 86 | } catch let error1 as NSError { 87 | error = error1 88 | soundEffectPlayer = nil 89 | } 90 | if let player = soundEffectPlayer { 91 | player.numberOfLoops = 0 92 | player.prepareToPlay() 93 | player.play() 94 | } else { 95 | print("Could not create audio player: \(error!)") 96 | } 97 | } 98 | } 99 | 100 | private let SKTAudioInstance = SKTAudio() 101 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/SKTUtils/CGFloat+Extensions.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import CoreGraphics 24 | 25 | /** The value of π as a CGFloat */ 26 | let π = CGFloat(M_PI) 27 | 28 | public extension CGFloat { 29 | /** 30 | * Converts an angle in degrees to radians. 31 | */ 32 | public func degreesToRadians() -> CGFloat { 33 | return π * self / 180.0 34 | } 35 | 36 | /** 37 | * Converts an angle in radians to degrees. 38 | */ 39 | public func radiansToDegrees() -> CGFloat { 40 | return self * 180.0 / π 41 | } 42 | 43 | /** 44 | * Ensures that the float value stays between the given values, inclusive. 45 | */ 46 | public func clamped(v1: CGFloat, _ v2: CGFloat) -> CGFloat { 47 | let min = v1 < v2 ? v1 : v2 48 | let max = v1 > v2 ? v1 : v2 49 | return self < min ? min : (self > max ? max : self) 50 | } 51 | 52 | /** 53 | * Ensures that the float value stays between the given values, inclusive. 54 | */ 55 | public mutating func clamp(v1: CGFloat, _ v2: CGFloat) -> CGFloat { 56 | self = clamped(v1: v1, v2) 57 | return self 58 | } 59 | 60 | /** 61 | * Returns 1.0 if a floating point value is positive; -1.0 if it is negative. 62 | */ 63 | public func sign() -> CGFloat { 64 | return (self >= 0.0) ? 1.0 : -1.0 65 | } 66 | 67 | /** 68 | * Returns a random floating point number between 0.0 and 1.0, inclusive. 69 | */ 70 | public static func random() -> CGFloat { 71 | return CGFloat(Float(arc4random()) / 0xFFFFFFFF) 72 | } 73 | 74 | /** 75 | * Returns a random floating point number in the range min...max, inclusive. 76 | */ 77 | public static func random(min: CGFloat, max: CGFloat) -> CGFloat { 78 | assert(min < max) 79 | return CGFloat.random() * (max - min) + min 80 | } 81 | 82 | /** 83 | * Randomly returns either 1.0 or -1.0. 84 | */ 85 | public static func randomSign() -> CGFloat { 86 | return (arc4random_uniform(2) == 0) ? 1.0 : -1.0 87 | } 88 | } 89 | 90 | /** 91 | * Returns the shortest angle between two angles. The result is always between 92 | * -π and π. 93 | */ 94 | public func shortestAngleBetween(angle1: CGFloat, angle2: CGFloat) -> CGFloat { 95 | let twoπ = π * 2.0 96 | var angle = (angle2 - angle1).truncatingRemainder(dividingBy: twoπ) 97 | if (angle >= π) { 98 | angle = angle - twoπ 99 | } 100 | if (angle <= -π) { 101 | angle = angle + twoπ 102 | } 103 | return angle 104 | } 105 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird.xcodeproj/xcuserdata/ZBKF001.xcuserdatad/xcschemes/Flappy Bird.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/SKTUtils/SKNode+Extensions.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import SpriteKit 24 | 25 | public extension SKNode { 26 | 27 | /** Lets you treat the node's scale as a CGPoint value. */ 28 | public var scaleAsPoint: CGPoint { 29 | get { 30 | return CGPoint(x: xScale, y: yScale) 31 | } 32 | set { 33 | xScale = newValue.x 34 | yScale = newValue.y 35 | } 36 | } 37 | 38 | /** 39 | * Runs an action on the node that performs a closure or function after 40 | * a given time. 41 | */ 42 | public func afterDelay(delay: TimeInterval, runBlock block: @escaping (() -> ())) { 43 | run(SKAction.sequence([SKAction.wait(forDuration: delay), SKAction.run(block)])) 44 | } 45 | 46 | /** 47 | * Makes this node the frontmost node in its parent. 48 | */ 49 | public func bringToFront() { 50 | if let parent = self.parent{ 51 | removeFromParent() 52 | parent.addChild(self) 53 | } 54 | } 55 | 56 | /** 57 | * Orients the node in the direction that it is moving by tweening its 58 | * rotation angle. This assumes that at 0 degrees the node is facing up. 59 | * 60 | * @param velocity The current speed and direction of the node. You can get 61 | * this from node.physicsBody.velocity. 62 | * @param rate How fast the node rotates. Must have a value between 0.0 and 63 | * 1.0, where smaller means slower; 1.0 is instantaneous. 64 | */ 65 | public func rotateToVelocity(velocity: CGVector, rate: CGFloat) { 66 | // Determine what the rotation angle of the node ought to be based on the 67 | // current velocity of its physics body. This assumes that at 0 degrees the 68 | // node is pointed up, not to the right, so to compensate we subtract π/4 69 | // (90 degrees) from the calculated angle. 70 | let newAngle = atan2(velocity.dy, velocity.dx) - π/2 71 | 72 | // This always makes the node rotate over the shortest possible distance. 73 | // Because the range of atan2() is -180 to 180 degrees, a rotation from, 74 | // -170 to -190 would otherwise be from -170 to 170, which makes the node 75 | // rotate the wrong way (and the long way) around. We adjust the angle to 76 | // go from 190 to 170 instead, which is equivalent to -170 to -190. 77 | if newAngle - zRotation > π { 78 | zRotation += π * 2.0 79 | } else if zRotation - newAngle > π { 80 | zRotation -= π * 2.0 81 | } 82 | 83 | // Use the "standard exponential slide" to slowly tween zRotation to the 84 | // new angle. The greater the value of rate, the faster this goes. 85 | zRotation += (newAngle - zRotation) * rate 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/SKTUtils/SKAction+SpecialEffects.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import SpriteKit 24 | 25 | public extension SKAction { 26 | /** 27 | * Creates a screen shake animation. 28 | * 29 | * @param node The node to shake. You cannot apply this effect to an SKScene. 30 | * @param amount The vector by which the node is displaced. 31 | * @param oscillations The number of oscillations; 10 is a good value. 32 | * @param duration How long the effect lasts. Shorter is better. 33 | */ 34 | public class func screenShakeWithNode(node: SKNode, amount: CGPoint, oscillations: Int, duration: TimeInterval) -> SKAction { 35 | let oldPosition = node.position 36 | let newPosition = oldPosition + amount 37 | let effect = SKTMoveEffect(node: node, duration: duration, startPosition: newPosition, endPosition: oldPosition) 38 | effect.timingFunction = SKTCreateShakeFunction(oscillations: oscillations) 39 | 40 | return SKAction.actionWithEffect(effect: effect) 41 | } 42 | 43 | /** 44 | * Creates a screen rotation animation. 45 | * 46 | * @param node You usually want to apply this effect to a pivot node that is 47 | * centered in the scene. You cannot apply the effect to an SKScene. 48 | * @param angle The angle in radians. 49 | * @param oscillations The number of oscillations; 10 is a good value. 50 | * @param duration How long the effect lasts. Shorter is better. 51 | */ 52 | public class func screenRotateWithNode(node: SKNode, angle: CGFloat, oscillations: Int, duration: TimeInterval) -> SKAction { 53 | let oldAngle = node.zRotation 54 | let newAngle = oldAngle + angle 55 | 56 | let effect = SKTRotateEffect(node: node, duration: duration, startAngle: newAngle, endAngle: oldAngle) 57 | effect.timingFunction = SKTCreateShakeFunction(oscillations: oscillations) 58 | 59 | return SKAction.actionWithEffect(effect: effect) 60 | } 61 | 62 | /** 63 | * Creates a screen zoom animation. 64 | * 65 | * @param node You usually want to apply this effect to a pivot node that is 66 | * centered in the scene. You cannot apply the effect to an SKScene. 67 | * @param amount How much to scale the node in the X and Y directions. 68 | * @param oscillations The number of oscillations; 10 is a good value. 69 | * @param duration How long the effect lasts. Shorter is better. 70 | */ 71 | public class func screenZoomWithNode(node: SKNode, amount: CGPoint, oscillations: Int, duration: TimeInterval) -> SKAction { 72 | let oldScale = CGPoint(x: node.xScale, y: node.yScale) 73 | let newScale = oldScale * amount 74 | 75 | let effect = SKTScaleEffect(node: node, duration: duration, startScale: newScale, endScale: oldScale) 76 | effect.timingFunction = SKTCreateShakeFunction(oscillations: oscillations) 77 | 78 | return SKAction.actionWithEffect(effect: effect) 79 | } 80 | 81 | /** 82 | * Causes the scene background to flash for duration seconds. 83 | */ 84 | public class func colorGlitchWithScene(scene: SKScene, originalColor: SKColor, duration: TimeInterval) -> SKAction { 85 | return SKAction.customAction(withDuration: duration) {(node, elapsedTime) in 86 | if elapsedTime < CGFloat(duration) { 87 | scene.backgroundColor = SKColorWithRGB(r: Int.random(0, max: 255), g: Int.random(0, max: 255), b: Int.random(0, max: 255)) 88 | // SKColorWithRGB(Int.random(0...255), g: Int.random(0...255), b: Int.random(0...255)) 89 | } else { 90 | scene.backgroundColor = originalColor 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/SKTUtils/SKTEffects.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import SpriteKit 24 | 25 | /** 26 | * Allows you to perform actions with custom timing functions. 27 | * 28 | * Unfortunately, SKAction does not have a concept of a timing function, so 29 | * we need to replicate the actions using SKTEffect subclasses. 30 | */ 31 | public class SKTEffect { 32 | unowned var node: SKNode 33 | var duration: TimeInterval 34 | public var timingFunction: ((CGFloat) -> CGFloat)? 35 | 36 | public init(node: SKNode, duration: TimeInterval) { 37 | self.node = node 38 | self.duration = duration 39 | timingFunction = SKTTimingFunctionLinear 40 | } 41 | 42 | public func update(t: CGFloat) { 43 | // subclasses implement this 44 | } 45 | } 46 | 47 | /** 48 | * Moves a node from its current position to a new position. 49 | */ 50 | public class SKTMoveEffect: SKTEffect { 51 | var startPosition: CGPoint 52 | var delta: CGPoint 53 | var previousPosition: CGPoint 54 | 55 | public init(node: SKNode, duration: TimeInterval, startPosition: CGPoint, endPosition: CGPoint) { 56 | previousPosition = node.position 57 | self.startPosition = startPosition 58 | delta = endPosition - startPosition 59 | super.init(node: node, duration: duration) 60 | } 61 | 62 | public override func update(t: CGFloat) { 63 | // This allows multiple SKTMoveEffect objects to modify the same node 64 | // at the same time. 65 | let newPosition = startPosition + delta*t 66 | let diff = newPosition - previousPosition 67 | previousPosition = newPosition 68 | node.position += diff 69 | } 70 | } 71 | 72 | /** 73 | * Scales a node to a certain scale factor. 74 | */ 75 | public class SKTScaleEffect: SKTEffect { 76 | var startScale: CGPoint 77 | var delta: CGPoint 78 | var previousScale: CGPoint 79 | 80 | public init(node: SKNode, duration: TimeInterval, startScale: CGPoint, endScale: CGPoint) { 81 | previousScale = CGPoint(x: node.xScale, y: node.yScale) 82 | self.startScale = startScale 83 | delta = endScale - startScale 84 | super.init(node: node, duration: duration) 85 | } 86 | 87 | public override func update(t: CGFloat) { 88 | let newScale = startScale + delta*t 89 | let diff = newScale / previousScale 90 | previousScale = newScale 91 | node.xScale *= diff.x 92 | node.yScale *= diff.y 93 | } 94 | } 95 | 96 | /** 97 | * Rotates a node to a certain angle. 98 | */ 99 | public class SKTRotateEffect: SKTEffect { 100 | var startAngle: CGFloat 101 | var delta: CGFloat 102 | var previousAngle: CGFloat 103 | 104 | public init(node: SKNode, duration: TimeInterval, startAngle: CGFloat, endAngle: CGFloat) { 105 | previousAngle = node.zRotation 106 | self.startAngle = startAngle 107 | delta = endAngle - startAngle 108 | super.init(node: node, duration: duration) 109 | } 110 | 111 | public override func update(t: CGFloat) { 112 | let newAngle = startAngle + delta*t 113 | let diff = newAngle - previousAngle 114 | previousAngle = newAngle 115 | node.zRotation += diff 116 | } 117 | } 118 | 119 | /** 120 | * Wrapper that allows you to use SKTEffect objects as regular SKActions. 121 | */ 122 | public extension SKAction { 123 | public class func actionWithEffect(effect: SKTEffect) -> SKAction { 124 | return SKAction.customAction(withDuration: effect.duration) { node, elapsedTime in 125 | var t = elapsedTime / CGFloat(effect.duration) 126 | 127 | if let timingFunction = effect.timingFunction { 128 | t = timingFunction(t) // the magic happens here 129 | } 130 | 131 | effect.update(t: t) 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/SKTUtils/CGVector+Extensions.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import CoreGraphics 24 | import SpriteKit 25 | 26 | public extension CGVector { 27 | /** 28 | * Creates a new CGVector given a CGPoint. 29 | */ 30 | public init(point: CGPoint) { 31 | self.init(dx: point.x, dy: point.y) 32 | } 33 | 34 | /** 35 | * Given an angle in radians, creates a vector of length 1.0 and returns the 36 | * result as a new CGVector. An angle of 0 is assumed to point to the right. 37 | */ 38 | public init(angle: CGFloat) { 39 | self.init(dx: cos(angle), dy: sin(angle)) 40 | } 41 | 42 | /** 43 | * Adds (dx, dy) to the vector. 44 | */ 45 | public mutating func offset(_ dx: CGFloat, dy: CGFloat) -> CGVector { 46 | self.dx += dx 47 | self.dy += dy 48 | return self 49 | } 50 | 51 | /** 52 | * Returns the length (magnitude) of the vector described by the CGVector. 53 | */ 54 | public func length() -> CGFloat { 55 | return sqrt(dx*dx + dy*dy) 56 | } 57 | 58 | /** 59 | * Returns the squared length of the vector described by the CGVector. 60 | */ 61 | public func lengthSquared() -> CGFloat { 62 | return dx*dx + dy*dy 63 | } 64 | 65 | /** 66 | * Normalizes the vector described by the CGVector to length 1.0 and returns 67 | * the result as a new CGVector. 68 | public */ 69 | func normalized() -> CGVector { 70 | let len = length() 71 | return len>0 ? self / len : CGVector.zero 72 | } 73 | 74 | /** 75 | * Normalizes the vector described by the CGVector to length 1.0. 76 | */ 77 | public mutating func normalize() -> CGVector { 78 | self = normalized() 79 | return self 80 | } 81 | 82 | /** 83 | * Calculates the distance between two CGVectors. Pythagoras! 84 | */ 85 | public func distanceTo(vector: CGVector) -> CGFloat { 86 | return (self - vector).length() 87 | } 88 | 89 | /** 90 | * Returns the angle in radians of the vector described by the CGVector. 91 | * The range of the angle is -π to π; an angle of 0 points to the right. 92 | */ 93 | public var angle: CGFloat { 94 | return atan2(dy, dx) 95 | } 96 | } 97 | 98 | /** 99 | * Adds two CGVector values and returns the result as a new CGVector. 100 | */ 101 | public func + (left: CGVector, right: CGVector) -> CGVector { 102 | return CGVector(dx: left.dx + right.dx, dy: left.dy + right.dy) 103 | } 104 | 105 | /** 106 | * Increments a CGVector with the value of another. 107 | */ 108 | public func += ( left: inout CGVector, right: CGVector) { 109 | left = left + right 110 | } 111 | 112 | /** 113 | * Subtracts two CGVector values and returns the result as a new CGVector. 114 | */ 115 | public func - (left: CGVector, right: CGVector) -> CGVector { 116 | return CGVector(dx: left.dx - right.dx, dy: left.dy - right.dy) 117 | } 118 | 119 | /** 120 | * Decrements a CGVector with the value of another. 121 | */ 122 | public func -= (left: inout CGVector, right: CGVector) { 123 | left = left - right 124 | } 125 | 126 | /** 127 | * Multiplies two CGVector values and returns the result as a new CGVector. 128 | */ 129 | public func * (left: CGVector, right: CGVector) -> CGVector { 130 | return CGVector(dx: left.dx * right.dx, dy: left.dy * right.dy) 131 | } 132 | 133 | /** 134 | * Multiplies a CGVector with another. 135 | */ 136 | public func *= (left: inout CGVector, right: CGVector) { 137 | left = left * right 138 | } 139 | 140 | /** 141 | * Multiplies the x and y fields of a CGVector with the same scalar value and 142 | * returns the result as a new CGVector. 143 | */ 144 | public func * (vector: CGVector, scalar: CGFloat) -> CGVector { 145 | return CGVector(dx: vector.dx * scalar, dy: vector.dy * scalar) 146 | } 147 | 148 | /** 149 | * Multiplies the x and y fields of a CGVector with the same scalar value. 150 | */ 151 | public func *= (vector: inout CGVector, scalar: CGFloat) { 152 | vector = vector * scalar 153 | } 154 | 155 | /** 156 | * Divides two CGVector values and returns the result as a new CGVector. 157 | */ 158 | public func / (left: CGVector, right: CGVector) -> CGVector { 159 | return CGVector(dx: left.dx / right.dx, dy: left.dy / right.dy) 160 | } 161 | 162 | /** 163 | * Divides a CGVector by another. 164 | */ 165 | public func /= (left: inout CGVector, right: CGVector) { 166 | left = left / right 167 | } 168 | 169 | /** 170 | * Divides the dx and dy fields of a CGVector by the same scalar value and 171 | * returns the result as a new CGVector. 172 | */ 173 | public func / (vector: CGVector, scalar: CGFloat) -> CGVector { 174 | return CGVector(dx: vector.dx / scalar, dy: vector.dy / scalar) 175 | } 176 | 177 | /** 178 | * Divides the dx and dy fields of a CGVector by the same scalar value. 179 | */ 180 | public func /= (vector: inout CGVector, scalar: CGFloat) { 181 | vector = vector / scalar 182 | } 183 | 184 | /** 185 | * Performs a linear interpolation between two CGVector values. 186 | */ 187 | public func lerp(_ start: CGVector, end: CGVector, t: CGFloat) -> CGVector { 188 | return CGVector(dx: start.dx + (end.dx - start.dx)*t, dy: start.dy + (end.dy - start.dy)*t) 189 | } 190 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/SKTUtils/CGPoint+Extensions.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import CoreGraphics 24 | import SpriteKit 25 | 26 | public extension CGPoint { 27 | /** 28 | * Creates a new CGPoint given a CGVector. 29 | */ 30 | public init(vector: CGVector) { 31 | self.init(x: vector.dx, y: vector.dy) 32 | } 33 | 34 | /** 35 | * Given an angle in radians, creates a vector of length 1.0 and returns the 36 | * result as a new CGPoint. An angle of 0 is assumed to point to the right. 37 | */ 38 | public init(angle: CGFloat) { 39 | self.init(x: cos(angle), y: sin(angle)) 40 | } 41 | 42 | /** 43 | * Adds (dx, dy) to the point. 44 | */ 45 | public mutating func offset(_ dx: CGFloat, dy: CGFloat) -> CGPoint { 46 | x += dx 47 | y += dy 48 | return self 49 | } 50 | 51 | /** 52 | * Returns the length (magnitude) of the vector described by the CGPoint. 53 | */ 54 | public func length() -> CGFloat { 55 | 56 | return sqrt(x*x + y*y) 57 | } 58 | 59 | /** 60 | * Returns the squared length of the vector described by the CGPoint. 61 | */ 62 | public func lengthSquared() -> CGFloat { 63 | return x*x + y*y 64 | } 65 | 66 | /** 67 | * Normalizes the vector described by the CGPoint to length 1.0 and returns 68 | * the result as a new CGPoint. 69 | */ 70 | func normalized() -> CGPoint { 71 | let len = length() 72 | return len>0 ? self / len : CGPoint.zero 73 | } 74 | 75 | /** 76 | * Normalizes the vector described by the CGPoint to length 1.0. 77 | */ 78 | public mutating func normalize() -> CGPoint { 79 | self = normalized() 80 | return self 81 | } 82 | 83 | /** 84 | * Calculates the distance between two CGPoints. Pythagoras! 85 | */ 86 | public func distanceTo(point: CGPoint) -> CGFloat { 87 | return (self - point).length() 88 | } 89 | 90 | /** 91 | * Returns the angle in radians of the vector described by the CGPoint. 92 | * The range of the angle is -π to π; an angle of 0 points to the right. 93 | */ 94 | public var angle: CGFloat { 95 | return atan2(y, x) 96 | } 97 | } 98 | 99 | /** 100 | * Adds two CGPoint values and returns the result as a new CGPoint. 101 | */ 102 | public func + (left: CGPoint, right: CGPoint) -> CGPoint { 103 | return CGPoint(x: left.x + right.x, y: left.y + right.y) 104 | } 105 | 106 | /** 107 | * Increments a CGPoint with the value of another. 108 | */ 109 | public func += ( left: inout CGPoint, right: CGPoint) { 110 | left = left + right 111 | } 112 | 113 | /** 114 | * Adds a CGVector to this CGPoint and returns the result as a new CGPoint. 115 | */ 116 | public func + (left: CGPoint, right: CGVector) -> CGPoint { 117 | return CGPoint(x: left.x + right.dx, y: left.y + right.dy) 118 | } 119 | 120 | /** 121 | * Increments a CGPoint with the value of a CGVector. 122 | */ 123 | public func += ( left: inout CGPoint, right: CGVector) { 124 | left = left + right 125 | } 126 | 127 | /** 128 | * Subtracts two CGPoint values and returns the result as a new CGPoint. 129 | */ 130 | public func - (left: CGPoint, right: CGPoint) -> CGPoint { 131 | return CGPoint(x: left.x - right.x, y: left.y - right.y) 132 | } 133 | 134 | /** 135 | * Decrements a CGPoint with the value of another. 136 | */ 137 | public func -= ( left: inout CGPoint, right: CGPoint) { 138 | left = left - right 139 | } 140 | 141 | /** 142 | * Subtracts a CGVector from a CGPoint and returns the result as a new CGPoint. 143 | */ 144 | public func - (left: CGPoint, right: CGVector) -> CGPoint { 145 | return CGPoint(x: left.x - right.dx, y: left.y - right.dy) 146 | } 147 | 148 | /** 149 | * Decrements a CGPoint with the value of a CGVector. 150 | */ 151 | public func -= ( left: inout CGPoint, right: CGVector) { 152 | left = left - right 153 | } 154 | 155 | /** 156 | * Multiplies two CGPoint values and returns the result as a new CGPoint. 157 | */ 158 | public func * (left: CGPoint, right: CGPoint) -> CGPoint { 159 | return CGPoint(x: left.x * right.x, y: left.y * right.y) 160 | } 161 | 162 | /** 163 | * Multiplies a CGPoint with another. 164 | */ 165 | public func *= ( left: inout CGPoint, right: CGPoint) { 166 | left = left * right 167 | } 168 | 169 | /** 170 | * Multiplies the x and y fields of a CGPoint with the same scalar value and 171 | * returns the result as a new CGPoint. 172 | */ 173 | public func * (point: CGPoint, scalar: CGFloat) -> CGPoint { 174 | return CGPoint(x: point.x * scalar, y: point.y * scalar) 175 | } 176 | 177 | /** 178 | * Multiplies the x and y fields of a CGPoint with the same scalar value. 179 | */ 180 | public func *= ( point: inout CGPoint, scalar: CGFloat) { 181 | point = point * scalar 182 | } 183 | 184 | /** 185 | * Multiplies a CGPoint with a CGVector and returns the result as a new CGPoint. 186 | */ 187 | public func * (left: CGPoint, right: CGVector) -> CGPoint { 188 | return CGPoint(x: left.x * right.dx, y: left.y * right.dy) 189 | } 190 | 191 | /** 192 | * Multiplies a CGPoint with a CGVector. 193 | */ 194 | public func *= ( left: inout CGPoint, right: CGVector) { 195 | left = left * right 196 | } 197 | 198 | /** 199 | * Divides two CGPoint values and returns the result as a new CGPoint. 200 | */ 201 | public func / (left: CGPoint, right: CGPoint) -> CGPoint { 202 | return CGPoint(x: left.x / right.x, y: left.y / right.y) 203 | } 204 | 205 | /** 206 | * Divides a CGPoint by another. 207 | */ 208 | public func /= ( left: inout CGPoint, right: CGPoint) { 209 | left = left / right 210 | } 211 | 212 | /** 213 | * Divides the x and y fields of a CGPoint by the same scalar value and returns 214 | * the result as a new CGPoint. 215 | */ 216 | public func / (point: CGPoint, scalar: CGFloat) -> CGPoint { 217 | return CGPoint(x: point.x / scalar, y: point.y / scalar) 218 | } 219 | 220 | /** 221 | * Divides the x and y fields of a CGPoint by the same scalar value. 222 | */ 223 | public func /= ( point: inout CGPoint, scalar: CGFloat) { 224 | point = point / scalar 225 | } 226 | 227 | /** 228 | * Divides a CGPoint by a CGVector and returns the result as a new CGPoint. 229 | */ 230 | public func / (left: CGPoint, right: CGVector) -> CGPoint { 231 | return CGPoint(x: left.x / right.dx, y: left.y / right.dy) 232 | } 233 | 234 | /** 235 | * Divides a CGPoint by a CGVector. 236 | */ 237 | public func /= ( left: inout CGPoint, right: CGVector) { 238 | left = left / right 239 | } 240 | 241 | /** 242 | * Performs a linear interpolation between two CGPoint values. 243 | */ 244 | public func lerp(_ start: CGPoint, end: CGPoint, t: CGFloat) -> CGPoint { 245 | return CGPoint(x: start.x + (end.x - start.x)*t, y: start.y + (end.y - start.y)*t) 246 | } 247 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/Resources/SKTUtils/SKTTimingFunctions.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Timing functions for SKTEffects. Based on Robert Penner's easing equations 3 | * http://robertpenner.com/easing/ and https://github.com/warrenm/AHEasing 4 | * 5 | * Copyright (c) 2013-2014 Razeware LLC 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | import Foundation 27 | import CoreGraphics 28 | 29 | public func SKTTimingFunctionLinear(t: CGFloat) -> CGFloat { 30 | return t 31 | } 32 | 33 | public func SKTTimingFunctionQuadraticEaseIn(t: CGFloat) -> CGFloat { 34 | return t * t 35 | } 36 | 37 | public func SKTTimingFunctionQuadraticEaseOut(t: CGFloat) -> CGFloat { 38 | return t * (2.0 - t) 39 | } 40 | 41 | public func SKTTimingFunctionQuadraticEaseInOut(t: CGFloat) -> CGFloat { 42 | if t < 0.5 { 43 | return 2.0 * t * t 44 | } else { 45 | let f = t - 1.0 46 | return 1.0 - 2.0 * f * f 47 | } 48 | } 49 | 50 | func SKTTimingFunctionCubicEaseIn(t: CGFloat) -> CGFloat { 51 | return t * t * t 52 | } 53 | 54 | func SKTTimingFunctionCubicEaseOut(t: CGFloat) -> CGFloat { 55 | let f = t - 1.0 56 | return 1.0 + f * f * f 57 | } 58 | 59 | public func SKTTimingFunctionCubicEaseInOut(t: CGFloat) -> CGFloat { 60 | if t < 0.5 { 61 | return 4.0 * t * t * t 62 | } else { 63 | let f = t - 1.0 64 | return 1.0 + 4.0 * f * f * f 65 | } 66 | } 67 | 68 | public func SKTTimingFunctionQuarticEaseIn(t: CGFloat) -> CGFloat { 69 | return t * t * t * t 70 | } 71 | 72 | public func SKTTimingFunctionQuarticEaseOut(t: CGFloat) -> CGFloat { 73 | let f = t - 1.0 74 | return 1.0 - f * f * f * f 75 | } 76 | 77 | public func SKTTimingFunctionQuarticEaseInOut(t: CGFloat) -> CGFloat { 78 | if t < 0.5 { 79 | return 8.0 * t * t * t * t 80 | } else { 81 | let f = t - 1.0 82 | return 1.0 - 8.0 * f * f * f * f 83 | } 84 | } 85 | 86 | public func SKTTimingFunctionQuinticEaseIn(t: CGFloat) -> CGFloat { 87 | return t * t * t * t * t 88 | } 89 | 90 | public func SKTTimingFunctionQuinticEaseOut(t: CGFloat) -> CGFloat { 91 | let f = t - 1.0 92 | return 1.0 + f * f * f * f * f 93 | } 94 | 95 | func SKTTimingFunctionQuinticEaseInOut(t: CGFloat) -> CGFloat { 96 | if t < 0.5 { 97 | return 16.0 * t * t * t * t * t 98 | } else { 99 | let f = t - 1.0 100 | return 1.0 + 16.0 * f * f * f * f * f 101 | } 102 | } 103 | 104 | public func SKTTimingFunctionSineEaseIn(t: CGFloat) -> CGFloat { 105 | return sin((t - 1.0) * π/2) + 1.0 106 | } 107 | 108 | public func SKTTimingFunctionSineEaseOut(t: CGFloat) -> CGFloat { 109 | return sin(t * π/2) 110 | } 111 | 112 | public func SKTTimingFunctionSineEaseInOut(t: CGFloat) -> CGFloat { 113 | return 0.5 * (1.0 - cos(t * π)) 114 | } 115 | 116 | public func SKTTimingFunctionCircularEaseIn(t: CGFloat) -> CGFloat { 117 | return 1.0 - sqrt(1.0 - t * t) 118 | } 119 | 120 | public func SKTTimingFunctionCircularEaseOut(t: CGFloat) -> CGFloat { 121 | return sqrt((2.0 - t) * t) 122 | } 123 | 124 | public func SKTTimingFunctionCircularEaseInOut(t: CGFloat) -> CGFloat { 125 | if t < 0.5 { 126 | return 0.5 * (1.0 - sqrt(1.0 - 4.0 * t * t)) 127 | } else { 128 | return 0.5 * sqrt(-4.0 * t * t + 8.0 * t - 3.0) + 0.5 129 | } 130 | } 131 | 132 | public func SKTTimingFunctionExponentialEaseIn(t: CGFloat) -> CGFloat { 133 | return (t == 0.0) ? t : pow(2.0, 10.0 * (t - 1.0)) 134 | } 135 | 136 | public func SKTTimingFunctionExponentialEaseOut(t: CGFloat) -> CGFloat { 137 | return (t == 1.0) ? t : 1.0 - pow(2.0, -10.0 * t) 138 | } 139 | 140 | public func SKTTimingFunctionExponentialEaseInOut(t: CGFloat) -> CGFloat { 141 | if t == 0.0 || t == 1.0 { 142 | return t 143 | } else if t < 0.5 { 144 | return 0.5 * pow(2.0, 20.0 * t - 10.0) 145 | } else { 146 | return 1.0 - 0.5 * pow(2.0, -20.0 * t + 10.0) 147 | } 148 | } 149 | 150 | public func SKTTimingFunctionElasticEaseIn(t: CGFloat) -> CGFloat { 151 | return sin(13.0 * π/2 * t) * pow(2.0, 10.0 * (t - 1.0)) 152 | } 153 | 154 | public func SKTTimingFunctionElasticEaseOut(t: CGFloat) -> CGFloat { 155 | return sin(-13.0 * π/2 * (t + 1.0)) * pow(2.0, -10.0 * t) + 1.0 156 | } 157 | 158 | public func SKTTimingFunctionElasticEaseInOut(t: CGFloat) -> CGFloat { 159 | if t < 0.5 { 160 | return 0.5 * sin(13.0 * π * t) * pow(2.0, 20.0 * t - 10.0) 161 | } else { 162 | return 0.5 * sin(-13.0 * π * t) * pow(2.0, -20.0 * t + 10.0) + 1.0 163 | } 164 | } 165 | 166 | public func SKTTimingFunctionBackEaseIn(t: CGFloat) -> CGFloat { 167 | let s: CGFloat = 1.70158 168 | return ((s + 1.0) * t - s) * t * t 169 | } 170 | 171 | public func SKTTimingFunctionBackEaseOut(t: CGFloat) -> CGFloat { 172 | let s: CGFloat = 1.70158 173 | let f = 1.0 - t 174 | return 1.0 - ((s + 1.0) * f - s) * f * f 175 | } 176 | 177 | public func SKTTimingFunctionBackEaseInOut(t: CGFloat) -> CGFloat { 178 | let s: CGFloat = 1.70158 179 | if t < 0.5 { 180 | let f = 2.0 * t 181 | return 0.5 * ((s + 1.0) * f - s) * f * f 182 | } else { 183 | let f = 2.0 * (1.0 - t) 184 | return 1.0 - 0.5 * ((s + 1.0) * f - s) * f * f 185 | } 186 | } 187 | 188 | public func SKTTimingFunctionExtremeBackEaseIn(t: CGFloat) -> CGFloat { 189 | return (t * t - sin(t * π)) * t 190 | } 191 | 192 | public func SKTTimingFunctionExtremeBackEaseOut(t: CGFloat) -> CGFloat { 193 | let f = 1.0 - t 194 | return 1.0 - (f * f - sin(f * π)) * f 195 | } 196 | 197 | public func SKTTimingFunctionExtremeBackEaseInOut(t: CGFloat) -> CGFloat { 198 | if t < 0.5 { 199 | let f = 2.0 * t 200 | return 0.5 * (f * f - sin(f * π)) * f 201 | } else { 202 | let f = 2.0 * (1.0 - t) 203 | return 1.0 - 0.5 * (f * f - sin(f * π)) * f 204 | } 205 | } 206 | 207 | public func SKTTimingFunctionBounceEaseIn(t: CGFloat) -> CGFloat { 208 | return 1.0 - SKTTimingFunctionBounceEaseOut(t: 1.0 - t) 209 | } 210 | 211 | public func SKTTimingFunctionBounceEaseOut(t: CGFloat) -> CGFloat { 212 | if t < 1.0 / 2.75 { 213 | return 7.5625 * t * t 214 | } else if t < 2.0 / 2.75 { 215 | let f = t - 1.5 / 2.75 216 | return 7.5625 * f * f + 0.75 217 | } else if t < 2.5 / 2.75 { 218 | let f = t - 2.25 / 2.75 219 | return 7.5625 * f * f + 0.9375 220 | } else { 221 | let f = t - 2.625 / 2.75 222 | return 7.5625 * f * f + 0.984375 223 | } 224 | } 225 | 226 | public func SKTTimingFunctionBounceEaseInOut(t: CGFloat) -> CGFloat { 227 | if t < 0.5 { 228 | return 0.5 * SKTTimingFunctionBounceEaseIn(t: t * 2.0) 229 | } else { 230 | return 0.5 * SKTTimingFunctionBounceEaseOut(t: t * 2.0 - 1.0) + 0.5 231 | } 232 | } 233 | 234 | public func SKTTimingFunctionSmoothstep(t: CGFloat) -> CGFloat { 235 | return t * t * (3 - 2 * t) 236 | } 237 | 238 | public func SKTCreateShakeFunction(oscillations: Int) -> (CGFloat) -> CGFloat { 239 | return {t in -pow(2.0, -10.0 * t) * sin(t * π * CGFloat(oscillations) * 2.0) + 1.0} 240 | } 241 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird/GameScene.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameScene.swift 3 | // Flappy Bird 4 | // 5 | // Created by i-Techsys.com on 16/12/10. 6 | // Copyright © 2016年 i-Techsys. All rights reserved. 7 | // // 多边形工具 - http://stackoverflow.com/questions/19040144 Skite 8 | 9 | import SpriteKit 10 | import GameplayKit 11 | 12 | class GameScene: SKScene { 13 | // MARK: - 属性 14 | let 游戏世界 = SKNode() 15 | var 游戏区域起始点: CGFloat = 0 16 | var 游戏区域的高度: CGFloat = 0 17 | let 主角 = SKSpriteNode(imageNamed: "Bird0") 18 | let 帽子🎩 = SKSpriteNode(imageNamed: "Sombrero") 19 | 20 | // MARK: - 变动属性 21 | var 上一次更新时间: TimeInterval = 0 22 | var dt: TimeInterval = 0 23 | 24 | let k重力: CGFloat = -400.0 25 | let k上冲速度: CGFloat = 200 26 | var 速度 = CGPoint.zero 27 | let k前景地面数 = 2 28 | let k前景移动速度: CGFloat = -150.0 29 | let k底部障碍物的最小乘数: CGFloat = 0.1 30 | let k底部障碍物的最大乘数: CGFloat = 0.6 31 | let k缺口参数: CGFloat = 3.5 32 | let k首次生成障碍延迟时间: TimeInterval = 1.75 33 | let k每次生成障碍延迟时间: TimeInterval = 1.5 34 | 35 | let k留白: CGFloat = 20 36 | let k字体名字 = "AmericanTypewriter-Bold" 37 | var 得分标签: SKLabelNode! 38 | var 当前分数 = 0 39 | let k动画延迟 = 0.3 40 | let k角色动画总帧数 = 4 41 | 42 | var 主角撞击了地面布尔类型: Bool = false 43 | var 主角撞击了障碍物布尔类型: Bool = false 44 | var 当前游戏状态: 游戏状态 = .主菜单 45 | 46 | // MARK: - 创建音效 47 | let 叮的音效 = SKAction.playSoundFileNamed("ding.wav", waitForCompletion: false) 48 | let 拍打的音效 = SKAction.playSoundFileNamed("flapping.wav", waitForCompletion: false) 49 | let 摔倒的音效 = SKAction.playSoundFileNamed("whack.wav", waitForCompletion: false) 50 | let 下落的音效 = SKAction.playSoundFileNamed("falling.wav", waitForCompletion: false) 51 | let 撞击地面的音效 = SKAction.playSoundFileNamed("hitGround.wav", waitForCompletion: false) 52 | let 砰的音效 = SKAction.playSoundFileNamed("pop.wav", waitForCompletion: false) 53 | let 得分的音效 = SKAction.playSoundFileNamed("coin.wav", waitForCompletion: false) 54 | 55 | override func didMove(to view: SKView) { 56 | // 设置物理引擎代理 57 | physicsWorld.contactDelegate = self 58 | 59 | // 关掉重力 60 | physicsWorld.gravity = CGVector.zero 61 | 62 | addChild(游戏世界) 63 | 64 | 切换到主菜单() 65 | } 66 | 67 | // MARK: - 游戏流程 68 | fileprivate func 创建障碍物(_ 图片名: String) -> SKSpriteNode { 69 | let 障碍物 = SKSpriteNode(imageNamed: 图片名) 70 | 障碍物.zPosition = 图层.障碍物.rawValue 71 | 障碍物.userData = NSMutableDictionary() 72 | 73 | let offsetX = 障碍物.size.width * 障碍物.anchorPoint.x 74 | let offsetY = 障碍物.size.height * 障碍物.anchorPoint.y 75 | let path = CGMutablePath() 76 | path.move(to: CGPoint(x: 4 - offsetX, y: 0 - offsetY), transform: CGAffineTransform.identity) 77 | path.addLine(to: CGPoint(x: 7 - offsetX, y: 307 - offsetY), transform: CGAffineTransform.identity) 78 | path.addLine(to: CGPoint(x: 47 - offsetX, y: 308 - offsetY), transform: CGAffineTransform.identity) 79 | path.addLine(to: CGPoint(x: 48 - offsetX, y: 1 - offsetY), transform: CGAffineTransform.identity) 80 | path.closeSubpath() 81 | 82 | 障碍物.physicsBody = SKPhysicsBody(polygonFrom: path) 83 | 障碍物.physicsBody?.categoryBitMask = 物理层.障碍物 84 | 障碍物.physicsBody?.collisionBitMask = 0 85 | 障碍物.physicsBody?.contactTestBitMask = 物理层.游戏角色 86 | 87 | return 障碍物 88 | } 89 | 90 | fileprivate func 生成障碍物() { 91 | let 底部障碍物 = 创建障碍物("CactusBottom") 92 | 底部障碍物.name = "底部障碍物" 93 | let 起始X坐标 = size.width + 底部障碍物.size.width/2 94 | let Y最小坐标 = (游戏区域起始点 - 底部障碍物.size.height/2) + 游戏区域的高度*k底部障碍物的最小乘数 95 | let Y最大坐标 = (游戏区域起始点 - 底部障碍物.size.height/2) + 游戏区域的高度*k底部障碍物的最大乘数 96 | 97 | 底部障碍物.position = CGPoint(x: 起始X坐标, y: CGFloat.random(min: Y最小坐标, max: Y最大坐标)) 98 | 游戏世界.addChild(底部障碍物) 99 | 100 | let 顶部障碍物 = 创建障碍物("CactusTop") 101 | 顶部障碍物.name = "顶部障碍物" 102 | 顶部障碍物.zPosition = CGFloat(180).degreesToRadians() 103 | 顶部障碍物.position = CGPoint(x: 起始X坐标, y: 底部障碍物.position.y + 底部障碍物.size.height/2 + 顶部障碍物.size.height/2 + 主角.size.height*k缺口参数) 104 | 游戏世界.addChild(顶部障碍物) 105 | 106 | let X轴移动距离 = -(size.width + 底部障碍物.size.width) 107 | let 移动持续时间 = X轴移动距离 / k前景移动速度 108 | 109 | let 移动的动作序列 = SKAction.sequence([ 110 | SKAction.moveBy(x: X轴移动距离, y: 0, duration: TimeInterval(移动持续时间)), 111 | SKAction.removeFromParent() 112 | ]) 113 | 底部障碍物.run(移动的动作序列) 114 | 顶部障碍物.run(移动的动作序列) 115 | } 116 | 117 | fileprivate func 无限重生障碍物() { 118 | let 首次延迟 = SKAction.wait(forDuration: k首次生成障碍延迟时间) 119 | let 重生障碍 = SKAction.run(生成障碍物) 120 | let 每次重生间隔 = SKAction.wait(forDuration: k每次生成障碍延迟时间) 121 | let 重生的动作队列 = SKAction.sequence([重生障碍,每次重生间隔]) 122 | let 无限重生 = SKAction.repeatForever(重生的动作队列) 123 | let 总的动作队列 = SKAction.sequence([首次延迟,无限重生]) 124 | run(总的动作队列, withKey: "重生") 125 | } 126 | 127 | // MARK: - Touch Begin 128 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 129 | guard let 点击 = touches.first else { return } 130 | 131 | let 点击位置 = 点击.location(in: self) 132 | 133 | switch 当前游戏状态 { 134 | case .主菜单: 135 | if 点击位置.y < size.height * 0.15 { 136 | 去学习() 137 | } else if 点击位置.x < size.width/2 { 138 | 切换到教程状态() 139 | } else { 140 | 去评价() 141 | } 142 | break 143 | case .教程: 144 | 切换到游戏状态() 145 | break 146 | case .游戏: 147 | // 增加上冲速度 148 | 主角飞一下() 149 | break 150 | case .跌落: 151 | break 152 | case .显示分数: 153 | break 154 | case .结束🔚: 155 | 切换到新游戏() 156 | break 157 | } 158 | } 159 | 160 | fileprivate func 主角飞一下() { 161 | // 播放音效 162 | run(拍打的音效) 163 | 速度 = CGPoint(x: 0, y: k上冲速度) 164 | 165 | /// 帽子的动画 166 | let 向上移动 = SKAction.moveBy(x: 0, y: 12, duration: 0.15) 167 | 向上移动.timingMode = .easeInEaseOut 168 | let 向下移动 = 向上移动.reversed() 169 | 帽子🎩.run(SKAction.sequence([向上移动, 向下移动])) 170 | } 171 | 172 | 173 | // MARK: - 更新 174 | override func update(_ 当前时间: TimeInterval) { 175 | if 上一次更新时间 > 0 { 176 | dt = 当前时间 - 上一次更新时间 177 | }else { 178 | dt = 0 179 | } 180 | 上一次更新时间 = 当前时间 181 | 182 | switch 当前游戏状态 { 183 | case .主菜单: 184 | 185 | break 186 | case .教程: 187 | // 切换到游戏状态() 188 | break 189 | case .游戏: 190 | 更新主角() 191 | 更新前景() 192 | 撞击了地面的检查() 193 | 撞击了障碍物的检查() 194 | 更新得分() 195 | break 196 | case .跌落: 197 | 更新主角() 198 | 撞击了地面的检查() 199 | break 200 | case .显示分数: 201 | break 202 | case .结束🔚: 203 | 切换到新游戏() 204 | break 205 | } 206 | } 207 | 208 | fileprivate func 更新主角() { 209 | let 加速度 = CGPoint(x: 0, y: k重力) 210 | 速度 = 速度 + 加速度 * CGFloat(dt) 211 | 主角.position = 主角.position + 速度 * CGFloat(dt) 212 | 213 | // 检测撞击地面时让其停留在地面上 214 | if 主角.position.y - 主角.size.height/2 < 游戏区域起始点 { 215 | 主角.position = CGPoint(x: 主角.position.x, y: 主角.size.height/2 + 游戏区域起始点) 216 | } 217 | } 218 | 219 | fileprivate func 更新前景() { 220 | 游戏世界.enumerateChildNodes(withName: "前景") { (匹配单位, _) in 221 | if let 前景 = 匹配单位 as? SKSpriteNode { 222 | let 地面的移动速度 = CGPoint(x: self.k前景移动速度, y: 0) 223 | 前景.position += 地面的移动速度 * CGFloat(self.dt) 224 | 225 | if 前景.position.x < -前景.size.width { 226 | 前景.position += CGPoint(x: 前景.size.width*CGFloat(self.k前景地面数), y: 0) 227 | } 228 | } 229 | } 230 | } 231 | } 232 | 233 | // MARK: - 设置的相关方法 234 | extension GameScene { 235 | fileprivate func 设置教程() { 236 | let 教程 = SKSpriteNode(imageNamed: "Tutorial") 237 | 教程.position = CGPoint(x: size.width * 0.5 , y: 游戏区域的高度 * 0.4 + 游戏区域起始点) 238 | 教程.name = "教程" 239 | 教程.zPosition = 图层.UI.rawValue 240 | 游戏世界.addChild(教程) 241 | 242 | let 准备 = SKSpriteNode(imageNamed: "Ready") 243 | 准备.position = CGPoint(x: size.width * 0.5, y: 游戏区域的高度 * 0.7 + 游戏区域起始点) 244 | 准备.name = "教程" 245 | 准备.zPosition = 图层.UI.rawValue 246 | 游戏世界.addChild(准备) 247 | 248 | let 向上移动 = SKAction.moveBy(x: 0, y: 50, duration: 0.4) 249 | 向上移动.timingMode = .easeInEaseOut 250 | let 向下移动 = 向上移动.reversed() 251 | 252 | 主角.run(SKAction.repeatForever(SKAction.sequence([ 253 | 向上移动,向下移动 254 | ])), withKey: "起飞") 255 | 256 | var 角色贴图组: Array = [] 257 | 258 | for i in 0.. 最高分() { 343 | 设置最高分(最高分: 当前分数) 344 | } 345 | 346 | let 记分板 = SKSpriteNode(imageNamed: "ScoreCard") 347 | 记分板.position = CGPoint(x: size.width/2, y: size.height/2) 348 | 记分板.zPosition = 图层.UI.rawValue 349 | 游戏世界.addChild(记分板) 350 | 351 | let 当前分数标签 = SKLabelNode(fontNamed: k字体名字) 352 | 当前分数标签.fontColor = SKColor(red: 101.0/255.0, green: 71.0/255.0, blue: 73.0/255.0, alpha: 1.0) 353 | 当前分数标签.position = CGPoint(x: -记分板.size.width / 4, y: -记分板.size.height / 3) 354 | 当前分数标签.text = "\(当前分数)" 355 | 当前分数标签.zPosition = 图层.UI.rawValue 356 | 记分板.addChild(当前分数标签) 357 | 358 | let 最高分标签 = SKLabelNode(fontNamed: k字体名字) 359 | 最高分标签.fontColor = SKColor(red: 101.0/255.0, green: 71.0/255.0, blue: 73.0/255.0, alpha: 1.0) 360 | 最高分标签.position = CGPoint(x: 记分板.size.width / 4, y: -记分板.size.height / 3) 361 | 最高分标签.text = "\(最高分())" 362 | 最高分标签.zPosition = 图层.UI.rawValue 363 | 记分板.addChild(最高分标签) 364 | 365 | let 游戏结束 = SKSpriteNode(imageNamed: "GameOver") 366 | 游戏结束.position = CGPoint(x: size.width/2, y: size.height/2 + 记分板.size.height/2 + k留白 + 游戏结束.size.height/2) 367 | 游戏结束.zPosition = 图层.UI.rawValue 368 | 游戏世界.addChild(游戏结束) 369 | 370 | let ok按钮 = SKSpriteNode(imageNamed: "Button") 371 | ok按钮.position = CGPoint(x: size.width/4, y: size.height/2 - 记分板.size.height/2 - k留白 - ok按钮.size.height/2) 372 | ok按钮.zPosition = 图层.UI.rawValue 373 | 游戏世界.addChild(ok按钮) 374 | 375 | let ok = SKSpriteNode(imageNamed: "OK") 376 | ok.position = CGPoint.zero 377 | ok.zPosition = 图层.UI.rawValue 378 | ok按钮.addChild(ok) 379 | 380 | let 分享按钮 = SKSpriteNode(imageNamed: "ButtonRight") 381 | 分享按钮.position = CGPoint(x: size.width * 0.75, y: size.height/2 - 记分板.size.height/2 - k留白 - 分享按钮.size.height/2) 382 | 分享按钮.zPosition = 图层.UI.rawValue 383 | 游戏世界.addChild(分享按钮) 384 | 385 | let 分享 = SKSpriteNode(imageNamed: "Share") 386 | 分享.position = CGPoint.zero 387 | 分享.zPosition = 图层.UI.rawValue 388 | 分享按钮.addChild(分享) 389 | 390 | 游戏结束.setScale(0) 391 | 游戏结束.alpha = 0 392 | let 动画组 = SKAction.group([ 393 | SKAction.fadeIn(withDuration: k动画延迟), 394 | SKAction.scale(to: 1.0, duration: k动画延迟) 395 | ]) 396 | 动画组.timingMode = .easeInEaseOut 397 | 398 | 游戏结束.run(SKAction.sequence([ 399 | SKAction.wait(forDuration: k动画延迟), 400 | 动画组 401 | ])) 402 | 403 | 记分板.position = CGPoint(x: size.width / 2, y: -记分板.size.height/2) 404 | let 向上移动的动画 = SKAction.move(to: CGPoint(x: size.width / 2, y: size.height / 2), duration: k动画延迟) 405 | 向上移动的动画.timingMode = .easeInEaseOut 406 | 记分板.run(SKAction.sequence([ 407 | SKAction.wait(forDuration: k动画延迟 * 2), 408 | 向上移动的动画 409 | ])) 410 | 411 | ok按钮.alpha = 0 412 | 分享按钮.alpha = 0 413 | 414 | let 渐变动画 = SKAction.sequence([ 415 | SKAction.wait(forDuration: k动画延迟 * 3), 416 | SKAction.fadeIn(withDuration: k动画延迟) 417 | ]) 418 | ok按钮.run(渐变动画) 419 | 分享按钮.run(渐变动画) 420 | 421 | let 声音特效 = SKAction.sequence([ 422 | SKAction.wait(forDuration: k动画延迟), 423 | 砰的音效, 424 | SKAction.wait(forDuration: k动画延迟), 425 | 砰的音效, 426 | SKAction.wait(forDuration: k动画延迟), 427 | 砰的音效, 428 | SKAction.run(切换到结束状态) 429 | ]) 430 | 431 | run(声音特效) 432 | } 433 | 434 | func 设置主菜单() { 435 | 436 | // logo 437 | 438 | let logo = SKSpriteNode(imageNamed: "Logo") 439 | logo.position = CGPoint(x: size.width/2, y: size.height * 0.8) 440 | logo.name = "主菜单" 441 | logo.zPosition = 图层.UI.rawValue 442 | 游戏世界.addChild(logo) 443 | 444 | // 开始游戏按钮 445 | 446 | let 开始游戏按钮 = SKSpriteNode(imageNamed: "Button") 447 | 开始游戏按钮.position = CGPoint(x: size.width * 0.25, y: size.height * 0.25) 448 | 开始游戏按钮.name = "主菜单" 449 | 开始游戏按钮.zPosition = 图层.UI.rawValue 450 | 游戏世界.addChild(开始游戏按钮) 451 | 452 | let 游戏 = SKSpriteNode(imageNamed: "Play") 453 | 游戏.position = CGPoint.zero 454 | 开始游戏按钮.addChild(游戏) 455 | 456 | // 评价按钮 457 | 458 | let 评价按钮 = SKSpriteNode(imageNamed: "Button") 459 | 评价按钮.position = CGPoint(x: size.width * 0.75, y: size.height * 0.25) 460 | 评价按钮.zPosition = 图层.UI.rawValue 461 | 评价按钮.name = "主菜单" 462 | 游戏世界.addChild(评价按钮) 463 | 464 | let 评价 = SKSpriteNode(imageNamed: "Rate") 465 | 评价.position = CGPoint.zero 466 | 评价按钮.addChild(评价) 467 | 468 | // 学习按钮 469 | 470 | let 学习 = SKSpriteNode(imageNamed: "button_learn") 471 | 学习.position = CGPoint(x: size.width * 0.5, y: 学习.size.height/2 + k留白) 472 | 学习.name = "主菜单" 473 | 学习.zPosition = 图层.UI.rawValue 474 | 游戏世界.addChild(学习) 475 | 476 | // 学习按钮的动画 477 | let 放大动画 = SKAction.scale(to: 1.02, duration: 0.75) 478 | 放大动画.timingMode = .easeInEaseOut 479 | 480 | let 缩小动画 = SKAction.scale(to: 0.98, duration: 0.75) 481 | 缩小动画.timingMode = .easeInEaseOut 482 | 483 | 学习.run(SKAction.repeatForever(SKAction.sequence([ 484 | 放大动画,缩小动画 485 | ])), withKey: "主菜单") 486 | } 487 | } 488 | 489 | extension GameScene: SKPhysicsContactDelegate { 490 | func didEnd(_ 碰撞双方: SKPhysicsContact) { 491 | let 被撞对象 = 碰撞双方.bodyA.categoryBitMask == 492 | 物理层.游戏角色 ? 碰撞双方.bodyB : 碰撞双方.bodyA 493 | 494 | if 被撞对象.categoryBitMask == 物理层.地面 { 495 | 主角撞击了地面布尔类型 = true 496 | } 497 | if 被撞对象.categoryBitMask == 物理层.障碍物 { 498 | 主角撞击了地面布尔类型 = true 499 | 主角撞击了障碍物布尔类型 = true 500 | } 501 | 502 | } 503 | 504 | func didBegin(_ contact: SKPhysicsContact) { 505 | 506 | } 507 | } 508 | 509 | 510 | // MARK: - 游戏状态 511 | extension GameScene { 512 | fileprivate func 撞击了障碍物的检查() { 513 | if 主角撞击了障碍物布尔类型 { 514 | 主角撞击了障碍物布尔类型 = false 515 | 切换到跌落状态() 516 | } 517 | } 518 | 519 | /// 更新得分 520 | func 更新得分() { 521 | 游戏世界.enumerateChildNodes(withName: "顶部障碍物") { (匹配单位, _) in 522 | if let 障碍物 = 匹配单位 as? SKSpriteNode { 523 | if let 已通过 = 障碍物.userData?["已通过"] as? NSNumber { 524 | if 已通过.boolValue { 525 | return // 已经计算过一次得分了 526 | } 527 | } 528 | 529 | if self.主角.position.x > (障碍物.position.x + 障碍物.size.width/2) { 530 | self.当前分数 += 1 531 | self.得分标签.text = "\(self.当前分数)" 532 | self.run(self.得分的音效) 533 | 534 | 障碍物.userData?["已通过"] = NSNumber(value: true) 535 | } 536 | } 537 | } 538 | } 539 | 540 | 541 | fileprivate func 停止重生障碍物() { 542 | removeAction(forKey: "重生") 543 | 游戏世界.enumerateChildNodes(withName: "底部障碍物") { (匹配单位, _) in 544 | 匹配单位.removeAllActions() 545 | } 546 | 游戏世界.enumerateChildNodes(withName: "顶部障碍物") { (匹配单位, _) in 547 | 匹配单位.removeAllActions() 548 | } 549 | } 550 | 551 | fileprivate func 撞击了地面的检查() { 552 | if 主角撞击了地面布尔类型 { 553 | 主角撞击了地面布尔类型 = false 554 | 速度 = CGPoint.zero 555 | 主角.zRotation = CGFloat(-90).degreesToRadians() 556 | 主角.position = CGPoint(x: 主角.position.x, y: 游戏区域起始点 + 主角.size.width/2) 557 | 558 | run(撞击地面的音效) 559 | 切换到显示分数的状态() 560 | } 561 | } 562 | 563 | // MARK: - 切换状态 564 | /// 切换到跌落状态 565 | fileprivate func 切换到跌落状态() { 566 | 当前游戏状态 = .跌落 567 | 568 | run(SKAction.sequence([ 569 | 摔倒的音效, 570 | SKAction.wait(forDuration: 0.1), 571 | 下落的音效 572 | ])) 573 | 574 | 主角.removeAllActions() 575 | 停止重生障碍物() 576 | } 577 | 578 | fileprivate func 切换到显示分数的状态() { 579 | 当前游戏状态 = .显示分数 580 | 主角.removeAllActions() 581 | 停止重生障碍物() 582 | 设置记分板() 583 | } 584 | 585 | fileprivate func 切换到主菜单() { 586 | 当前游戏状态 = .主菜单 587 | 588 | 设置背景() 589 | 设置前景() 590 | 设置主角🐦() 591 | 设置帽子🎩() 592 | 设置主菜单() 593 | } 594 | 595 | 596 | fileprivate func 切换到教程状态() { 597 | 当前游戏状态 = .教程 598 | 599 | 游戏世界.enumerateChildNodes(withName: "主菜单") { (匹配单位, _) in 600 | 匹配单位.run(SKAction.sequence([ 601 | SKAction.fadeOut(withDuration: 0.05), 602 | SKAction.removeFromParent() ])) 603 | } 604 | 605 | 设置得分标签() 606 | 设置教程() 607 | } 608 | 609 | fileprivate func 切换到游戏状态() { 610 | 当前游戏状态 = .游戏 611 | 612 | 游戏世界.enumerateChildNodes(withName: "教程") { (匹配单位, _) in 613 | 匹配单位.run(SKAction.sequence([ 614 | SKAction.fadeOut(withDuration: 0.05), 615 | SKAction.removeFromParent() ])) 616 | } 617 | 618 | 无限重生障碍物() 619 | 主角飞一下() 620 | } 621 | } 622 | 623 | // MARK: 分数 624 | extension GameScene { 625 | 626 | func 最高分() -> Int { 627 | return UserDefaults.standard.integer(forKey: "最高分") 628 | } 629 | 630 | func 设置最高分(最高分: Int) { 631 | UserDefaults.standard.set(最高分, forKey: "最高分") 632 | UserDefaults.standard.synchronize() 633 | } 634 | 635 | func 切换到新游戏() { 636 | run(砰的音效) 637 | 638 | let 新的游戏场景 = GameScene.init(size: size) 639 | let 切换特效 = SKTransition.fade(with: SKColor.black, duration: 0.05) 640 | view?.presentScene(新的游戏场景, transition: 切换特效) 641 | } 642 | 643 | func 切换到结束状态() { 644 | 当前游戏状态 = .结束🔚 645 | } 646 | } 647 | 648 | // MARK: - 其他 https://github.com/LYM-mg/MGFlappy-Bird 649 | extension GameScene { 650 | fileprivate func 去学习() { 651 | let 学习代码网址 = "https://github.com/LYM-mg/MGFlappy-Bird" 652 | guard let url = URL(string: 学习代码网址) else { return } 653 | if UIApplication.shared.canOpenURL(url) { 654 | UIApplication.shared.openURL(url) 655 | } 656 | } 657 | 658 | fileprivate func 去评价() { 659 | let appStore网址 = "http://itunes.apple.com/app/id1077251372?mt=8" 660 | guard let url = URL(string: appStore网址) else { return } 661 | if UIApplication.shared.canOpenURL(url) { 662 | UIApplication.shared.openURL(url) 663 | } 664 | } 665 | } 666 | -------------------------------------------------------------------------------- /Flappy Bird/Flappy Bird.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C09C0B431DFEBEAB006E2E9B /* BitMaskType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C09C0B421DFEBEAB006E2E9B /* BitMaskType.swift */; }; 11 | C0D88D531E0C077B002630B5 /* MGBird.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D88D521E0C077B002630B5 /* MGBird.swift */; }; 12 | C0F7BFF51DFC128600948E16 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7BFF41DFC128600948E16 /* AppDelegate.swift */; }; 13 | C0F7BFF91DFC128600948E16 /* Actions.sks in Resources */ = {isa = PBXBuildFile; fileRef = C0F7BFF81DFC128600948E16 /* Actions.sks */; }; 14 | C0F7BFFB1DFC128600948E16 /* GameScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7BFFA1DFC128600948E16 /* GameScene.swift */; }; 15 | C0F7BFFD1DFC128600948E16 /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7BFFC1DFC128600948E16 /* GameViewController.swift */; }; 16 | C0F7C0001DFC128600948E16 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C0F7BFFE1DFC128600948E16 /* Main.storyboard */; }; 17 | C0F7C0021DFC128600948E16 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C0F7C0011DFC128600948E16 /* Assets.xcassets */; }; 18 | C0F7C0051DFC128600948E16 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C0F7C0031DFC128600948E16 /* LaunchScreen.storyboard */; }; 19 | C0F7C0581DFC194400948E16 /* backgrounds.atlas in Resources */ = {isa = PBXBuildFile; fileRef = C0F7C0411DFC194400948E16 /* backgrounds.atlas */; }; 20 | C0F7C0591DFC194400948E16 /* sprites.atlas in Resources */ = {isa = PBXBuildFile; fileRef = C0F7C0421DFC194400948E16 /* sprites.atlas */; }; 21 | C0F7C0661DFC194400948E16 /* coin.wav in Resources */ = {isa = PBXBuildFile; fileRef = C0F7C0511DFC194400948E16 /* coin.wav */; }; 22 | C0F7C0671DFC194400948E16 /* ding.wav in Resources */ = {isa = PBXBuildFile; fileRef = C0F7C0521DFC194400948E16 /* ding.wav */; }; 23 | C0F7C0681DFC194400948E16 /* falling.wav in Resources */ = {isa = PBXBuildFile; fileRef = C0F7C0531DFC194400948E16 /* falling.wav */; }; 24 | C0F7C0691DFC194400948E16 /* flapping.wav in Resources */ = {isa = PBXBuildFile; fileRef = C0F7C0541DFC194400948E16 /* flapping.wav */; }; 25 | C0F7C06A1DFC194400948E16 /* hitGround.wav in Resources */ = {isa = PBXBuildFile; fileRef = C0F7C0551DFC194400948E16 /* hitGround.wav */; }; 26 | C0F7C06B1DFC194400948E16 /* pop.wav in Resources */ = {isa = PBXBuildFile; fileRef = C0F7C0561DFC194400948E16 /* pop.wav */; }; 27 | C0F7C06C1DFC194400948E16 /* whack.wav in Resources */ = {isa = PBXBuildFile; fileRef = C0F7C0571DFC194400948E16 /* whack.wav */; }; 28 | C0F7C07A1DFC207000948E16 /* CGFloat+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7C06E1DFC207000948E16 /* CGFloat+Extensions.swift */; }; 29 | C0F7C07B1DFC207000948E16 /* CGPoint+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7C06F1DFC207000948E16 /* CGPoint+Extensions.swift */; }; 30 | C0F7C07C1DFC207000948E16 /* CGVector+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7C0701DFC207000948E16 /* CGVector+Extensions.swift */; }; 31 | C0F7C07D1DFC207000948E16 /* Int+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7C0711DFC207000948E16 /* Int+Extensions.swift */; }; 32 | C0F7C07E1DFC207000948E16 /* SKAction+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7C0721DFC207000948E16 /* SKAction+Extensions.swift */; }; 33 | C0F7C07F1DFC207000948E16 /* SKAction+SpecialEffects.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7C0731DFC207000948E16 /* SKAction+SpecialEffects.swift */; }; 34 | C0F7C0801DFC207000948E16 /* SKColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7C0741DFC207000948E16 /* SKColor+Extensions.swift */; }; 35 | C0F7C0811DFC207000948E16 /* SKNode+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7C0751DFC207000948E16 /* SKNode+Extensions.swift */; }; 36 | C0F7C0821DFC207000948E16 /* SKTAudio.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7C0761DFC207000948E16 /* SKTAudio.swift */; }; 37 | C0F7C0831DFC207000948E16 /* SKTEffects.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7C0771DFC207000948E16 /* SKTEffects.swift */; }; 38 | C0F7C0841DFC207000948E16 /* SKTTimingFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7C0781DFC207000948E16 /* SKTTimingFunctions.swift */; }; 39 | C0F7C0851DFC207000948E16 /* Vector3.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F7C0791DFC207000948E16 /* Vector3.swift */; }; 40 | /* End PBXBuildFile section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | C09C0B421DFEBEAB006E2E9B /* BitMaskType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BitMaskType.swift; sourceTree = ""; }; 44 | C0D88D521E0C077B002630B5 /* MGBird.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MGBird.swift; sourceTree = ""; }; 45 | C0F7BFF11DFC128600948E16 /* MG Bird.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "MG Bird.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | C0F7BFF41DFC128600948E16 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 47 | C0F7BFF81DFC128600948E16 /* Actions.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = Actions.sks; sourceTree = ""; }; 48 | C0F7BFFA1DFC128600948E16 /* GameScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameScene.swift; sourceTree = ""; }; 49 | C0F7BFFC1DFC128600948E16 /* GameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; }; 50 | C0F7BFFF1DFC128600948E16 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 51 | C0F7C0011DFC128600948E16 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 52 | C0F7C0041DFC128600948E16 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 53 | C0F7C0061DFC128600948E16 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54 | C0F7C0411DFC194400948E16 /* backgrounds.atlas */ = {isa = PBXFileReference; lastKnownFileType = folder.skatlas; path = backgrounds.atlas; sourceTree = ""; }; 55 | C0F7C0421DFC194400948E16 /* sprites.atlas */ = {isa = PBXFileReference; lastKnownFileType = folder.skatlas; path = sprites.atlas; sourceTree = ""; }; 56 | C0F7C0511DFC194400948E16 /* coin.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = coin.wav; sourceTree = ""; }; 57 | C0F7C0521DFC194400948E16 /* ding.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = ding.wav; sourceTree = ""; }; 58 | C0F7C0531DFC194400948E16 /* falling.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = falling.wav; sourceTree = ""; }; 59 | C0F7C0541DFC194400948E16 /* flapping.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = flapping.wav; sourceTree = ""; }; 60 | C0F7C0551DFC194400948E16 /* hitGround.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = hitGround.wav; sourceTree = ""; }; 61 | C0F7C0561DFC194400948E16 /* pop.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = pop.wav; sourceTree = ""; }; 62 | C0F7C0571DFC194400948E16 /* whack.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = whack.wav; sourceTree = ""; }; 63 | C0F7C06E1DFC207000948E16 /* CGFloat+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGFloat+Extensions.swift"; sourceTree = ""; }; 64 | C0F7C06F1DFC207000948E16 /* CGPoint+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGPoint+Extensions.swift"; sourceTree = ""; }; 65 | C0F7C0701DFC207000948E16 /* CGVector+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGVector+Extensions.swift"; sourceTree = ""; }; 66 | C0F7C0711DFC207000948E16 /* Int+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Int+Extensions.swift"; sourceTree = ""; }; 67 | C0F7C0721DFC207000948E16 /* SKAction+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SKAction+Extensions.swift"; sourceTree = ""; }; 68 | C0F7C0731DFC207000948E16 /* SKAction+SpecialEffects.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SKAction+SpecialEffects.swift"; sourceTree = ""; }; 69 | C0F7C0741DFC207000948E16 /* SKColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SKColor+Extensions.swift"; sourceTree = ""; }; 70 | C0F7C0751DFC207000948E16 /* SKNode+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SKNode+Extensions.swift"; sourceTree = ""; }; 71 | C0F7C0761DFC207000948E16 /* SKTAudio.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SKTAudio.swift; sourceTree = ""; }; 72 | C0F7C0771DFC207000948E16 /* SKTEffects.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SKTEffects.swift; sourceTree = ""; }; 73 | C0F7C0781DFC207000948E16 /* SKTTimingFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SKTTimingFunctions.swift; sourceTree = ""; }; 74 | C0F7C0791DFC207000948E16 /* Vector3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vector3.swift; sourceTree = ""; }; 75 | /* End PBXFileReference section */ 76 | 77 | /* Begin PBXFrameworksBuildPhase section */ 78 | C0F7BFEE1DFC128600948E16 /* Frameworks */ = { 79 | isa = PBXFrameworksBuildPhase; 80 | buildActionMask = 2147483647; 81 | files = ( 82 | ); 83 | runOnlyForDeploymentPostprocessing = 0; 84 | }; 85 | /* End PBXFrameworksBuildPhase section */ 86 | 87 | /* Begin PBXGroup section */ 88 | C09C0B411DFEBE6F006E2E9B /* Class */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | C09C0B421DFEBEAB006E2E9B /* BitMaskType.swift */, 92 | C0D88D521E0C077B002630B5 /* MGBird.swift */, 93 | ); 94 | path = Class; 95 | sourceTree = ""; 96 | }; 97 | C0F7BFE81DFC128600948E16 = { 98 | isa = PBXGroup; 99 | children = ( 100 | C0F7BFF31DFC128600948E16 /* Flappy Bird */, 101 | C0F7BFF21DFC128600948E16 /* Products */, 102 | ); 103 | sourceTree = ""; 104 | }; 105 | C0F7BFF21DFC128600948E16 /* Products */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | C0F7BFF11DFC128600948E16 /* MG Bird.app */, 109 | ); 110 | name = Products; 111 | sourceTree = ""; 112 | }; 113 | C0F7BFF31DFC128600948E16 /* Flappy Bird */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | C0F7C03F1DFC194400948E16 /* Resources */, 117 | C09C0B411DFEBE6F006E2E9B /* Class */, 118 | C0F7BFF41DFC128600948E16 /* AppDelegate.swift */, 119 | C0F7BFF81DFC128600948E16 /* Actions.sks */, 120 | C0F7BFFA1DFC128600948E16 /* GameScene.swift */, 121 | C0F7BFFC1DFC128600948E16 /* GameViewController.swift */, 122 | C0F7BFFE1DFC128600948E16 /* Main.storyboard */, 123 | C0F7C0011DFC128600948E16 /* Assets.xcassets */, 124 | C0F7C0031DFC128600948E16 /* LaunchScreen.storyboard */, 125 | C0F7C0061DFC128600948E16 /* Info.plist */, 126 | ); 127 | path = "Flappy Bird"; 128 | sourceTree = ""; 129 | }; 130 | C0F7C03F1DFC194400948E16 /* Resources */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | C0F7C0401DFC194400948E16 /* Art */, 134 | C0F7C06D1DFC207000948E16 /* SKTUtils */, 135 | C0F7C0501DFC194400948E16 /* Sounds */, 136 | ); 137 | path = Resources; 138 | sourceTree = ""; 139 | }; 140 | C0F7C0401DFC194400948E16 /* Art */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | C0F7C0411DFC194400948E16 /* backgrounds.atlas */, 144 | C0F7C0421DFC194400948E16 /* sprites.atlas */, 145 | ); 146 | path = Art; 147 | sourceTree = ""; 148 | }; 149 | C0F7C0501DFC194400948E16 /* Sounds */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | C0F7C0511DFC194400948E16 /* coin.wav */, 153 | C0F7C0521DFC194400948E16 /* ding.wav */, 154 | C0F7C0531DFC194400948E16 /* falling.wav */, 155 | C0F7C0541DFC194400948E16 /* flapping.wav */, 156 | C0F7C0551DFC194400948E16 /* hitGround.wav */, 157 | C0F7C0561DFC194400948E16 /* pop.wav */, 158 | C0F7C0571DFC194400948E16 /* whack.wav */, 159 | ); 160 | path = Sounds; 161 | sourceTree = ""; 162 | }; 163 | C0F7C06D1DFC207000948E16 /* SKTUtils */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | C0F7C06E1DFC207000948E16 /* CGFloat+Extensions.swift */, 167 | C0F7C06F1DFC207000948E16 /* CGPoint+Extensions.swift */, 168 | C0F7C0701DFC207000948E16 /* CGVector+Extensions.swift */, 169 | C0F7C0711DFC207000948E16 /* Int+Extensions.swift */, 170 | C0F7C0721DFC207000948E16 /* SKAction+Extensions.swift */, 171 | C0F7C0731DFC207000948E16 /* SKAction+SpecialEffects.swift */, 172 | C0F7C0741DFC207000948E16 /* SKColor+Extensions.swift */, 173 | C0F7C0751DFC207000948E16 /* SKNode+Extensions.swift */, 174 | C0F7C0761DFC207000948E16 /* SKTAudio.swift */, 175 | C0F7C0771DFC207000948E16 /* SKTEffects.swift */, 176 | C0F7C0781DFC207000948E16 /* SKTTimingFunctions.swift */, 177 | C0F7C0791DFC207000948E16 /* Vector3.swift */, 178 | ); 179 | path = SKTUtils; 180 | sourceTree = ""; 181 | }; 182 | /* End PBXGroup section */ 183 | 184 | /* Begin PBXNativeTarget section */ 185 | C0F7BFF01DFC128600948E16 /* Flappy Bird */ = { 186 | isa = PBXNativeTarget; 187 | buildConfigurationList = C0F7C0091DFC128600948E16 /* Build configuration list for PBXNativeTarget "Flappy Bird" */; 188 | buildPhases = ( 189 | C0F7BFED1DFC128600948E16 /* Sources */, 190 | C0F7BFEE1DFC128600948E16 /* Frameworks */, 191 | C0F7BFEF1DFC128600948E16 /* Resources */, 192 | ); 193 | buildRules = ( 194 | ); 195 | dependencies = ( 196 | ); 197 | name = "Flappy Bird"; 198 | productName = "Flappy Bird"; 199 | productReference = C0F7BFF11DFC128600948E16 /* MG Bird.app */; 200 | productType = "com.apple.product-type.application"; 201 | }; 202 | /* End PBXNativeTarget section */ 203 | 204 | /* Begin PBXProject section */ 205 | C0F7BFE91DFC128600948E16 /* Project object */ = { 206 | isa = PBXProject; 207 | attributes = { 208 | LastSwiftUpdateCheck = 0800; 209 | LastUpgradeCheck = 0800; 210 | ORGANIZATIONNAME = "i-Techsys"; 211 | TargetAttributes = { 212 | C0F7BFF01DFC128600948E16 = { 213 | CreatedOnToolsVersion = 8.0; 214 | ProvisioningStyle = Automatic; 215 | }; 216 | }; 217 | }; 218 | buildConfigurationList = C0F7BFEC1DFC128600948E16 /* Build configuration list for PBXProject "Flappy Bird" */; 219 | compatibilityVersion = "Xcode 3.2"; 220 | developmentRegion = English; 221 | hasScannedForEncodings = 0; 222 | knownRegions = ( 223 | en, 224 | Base, 225 | ); 226 | mainGroup = C0F7BFE81DFC128600948E16; 227 | productRefGroup = C0F7BFF21DFC128600948E16 /* Products */; 228 | projectDirPath = ""; 229 | projectRoot = ""; 230 | targets = ( 231 | C0F7BFF01DFC128600948E16 /* Flappy Bird */, 232 | ); 233 | }; 234 | /* End PBXProject section */ 235 | 236 | /* Begin PBXResourcesBuildPhase section */ 237 | C0F7BFEF1DFC128600948E16 /* Resources */ = { 238 | isa = PBXResourcesBuildPhase; 239 | buildActionMask = 2147483647; 240 | files = ( 241 | C0F7C06C1DFC194400948E16 /* whack.wav in Resources */, 242 | C0F7C0001DFC128600948E16 /* Main.storyboard in Resources */, 243 | C0F7C0661DFC194400948E16 /* coin.wav in Resources */, 244 | C0F7C0021DFC128600948E16 /* Assets.xcassets in Resources */, 245 | C0F7C0581DFC194400948E16 /* backgrounds.atlas in Resources */, 246 | C0F7C0051DFC128600948E16 /* LaunchScreen.storyboard in Resources */, 247 | C0F7C06A1DFC194400948E16 /* hitGround.wav in Resources */, 248 | C0F7C06B1DFC194400948E16 /* pop.wav in Resources */, 249 | C0F7C0591DFC194400948E16 /* sprites.atlas in Resources */, 250 | C0F7C0671DFC194400948E16 /* ding.wav in Resources */, 251 | C0F7C0691DFC194400948E16 /* flapping.wav in Resources */, 252 | C0F7BFF91DFC128600948E16 /* Actions.sks in Resources */, 253 | C0F7C0681DFC194400948E16 /* falling.wav in Resources */, 254 | ); 255 | runOnlyForDeploymentPostprocessing = 0; 256 | }; 257 | /* End PBXResourcesBuildPhase section */ 258 | 259 | /* Begin PBXSourcesBuildPhase section */ 260 | C0F7BFED1DFC128600948E16 /* Sources */ = { 261 | isa = PBXSourcesBuildPhase; 262 | buildActionMask = 2147483647; 263 | files = ( 264 | C0F7BFFB1DFC128600948E16 /* GameScene.swift in Sources */, 265 | C0D88D531E0C077B002630B5 /* MGBird.swift in Sources */, 266 | C0F7C07B1DFC207000948E16 /* CGPoint+Extensions.swift in Sources */, 267 | C0F7C0841DFC207000948E16 /* SKTTimingFunctions.swift in Sources */, 268 | C0F7C0831DFC207000948E16 /* SKTEffects.swift in Sources */, 269 | C0F7C07F1DFC207000948E16 /* SKAction+SpecialEffects.swift in Sources */, 270 | C0F7C07C1DFC207000948E16 /* CGVector+Extensions.swift in Sources */, 271 | C0F7C07E1DFC207000948E16 /* SKAction+Extensions.swift in Sources */, 272 | C0F7C0801DFC207000948E16 /* SKColor+Extensions.swift in Sources */, 273 | C0F7BFFD1DFC128600948E16 /* GameViewController.swift in Sources */, 274 | C09C0B431DFEBEAB006E2E9B /* BitMaskType.swift in Sources */, 275 | C0F7C07D1DFC207000948E16 /* Int+Extensions.swift in Sources */, 276 | C0F7C0811DFC207000948E16 /* SKNode+Extensions.swift in Sources */, 277 | C0F7C0821DFC207000948E16 /* SKTAudio.swift in Sources */, 278 | C0F7C07A1DFC207000948E16 /* CGFloat+Extensions.swift in Sources */, 279 | C0F7C0851DFC207000948E16 /* Vector3.swift in Sources */, 280 | C0F7BFF51DFC128600948E16 /* AppDelegate.swift in Sources */, 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | }; 284 | /* End PBXSourcesBuildPhase section */ 285 | 286 | /* Begin PBXVariantGroup section */ 287 | C0F7BFFE1DFC128600948E16 /* Main.storyboard */ = { 288 | isa = PBXVariantGroup; 289 | children = ( 290 | C0F7BFFF1DFC128600948E16 /* Base */, 291 | ); 292 | name = Main.storyboard; 293 | sourceTree = ""; 294 | }; 295 | C0F7C0031DFC128600948E16 /* LaunchScreen.storyboard */ = { 296 | isa = PBXVariantGroup; 297 | children = ( 298 | C0F7C0041DFC128600948E16 /* Base */, 299 | ); 300 | name = LaunchScreen.storyboard; 301 | sourceTree = ""; 302 | }; 303 | /* End PBXVariantGroup section */ 304 | 305 | /* Begin XCBuildConfiguration section */ 306 | C0F7C0071DFC128600948E16 /* Debug */ = { 307 | isa = XCBuildConfiguration; 308 | buildSettings = { 309 | ALWAYS_SEARCH_USER_PATHS = NO; 310 | CLANG_ANALYZER_NONNULL = YES; 311 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 312 | CLANG_CXX_LIBRARY = "libc++"; 313 | CLANG_ENABLE_MODULES = YES; 314 | CLANG_ENABLE_OBJC_ARC = YES; 315 | CLANG_WARN_BOOL_CONVERSION = YES; 316 | CLANG_WARN_CONSTANT_CONVERSION = YES; 317 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 318 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 319 | CLANG_WARN_EMPTY_BODY = YES; 320 | CLANG_WARN_ENUM_CONVERSION = YES; 321 | CLANG_WARN_INFINITE_RECURSION = YES; 322 | CLANG_WARN_INT_CONVERSION = YES; 323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 324 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 325 | CLANG_WARN_UNREACHABLE_CODE = YES; 326 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 327 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 328 | COPY_PHASE_STRIP = NO; 329 | DEBUG_INFORMATION_FORMAT = dwarf; 330 | ENABLE_STRICT_OBJC_MSGSEND = YES; 331 | ENABLE_TESTABILITY = YES; 332 | GCC_C_LANGUAGE_STANDARD = gnu99; 333 | GCC_DYNAMIC_NO_PIC = NO; 334 | GCC_NO_COMMON_BLOCKS = YES; 335 | GCC_OPTIMIZATION_LEVEL = 0; 336 | GCC_PREPROCESSOR_DEFINITIONS = ( 337 | "DEBUG=1", 338 | "$(inherited)", 339 | ); 340 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 341 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 342 | GCC_WARN_UNDECLARED_SELECTOR = YES; 343 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 344 | GCC_WARN_UNUSED_FUNCTION = YES; 345 | GCC_WARN_UNUSED_VARIABLE = YES; 346 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 347 | MTL_ENABLE_DEBUG_INFO = YES; 348 | ONLY_ACTIVE_ARCH = YES; 349 | SDKROOT = iphoneos; 350 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 351 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 352 | }; 353 | name = Debug; 354 | }; 355 | C0F7C0081DFC128600948E16 /* Release */ = { 356 | isa = XCBuildConfiguration; 357 | buildSettings = { 358 | ALWAYS_SEARCH_USER_PATHS = NO; 359 | CLANG_ANALYZER_NONNULL = YES; 360 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 361 | CLANG_CXX_LIBRARY = "libc++"; 362 | CLANG_ENABLE_MODULES = YES; 363 | CLANG_ENABLE_OBJC_ARC = YES; 364 | CLANG_WARN_BOOL_CONVERSION = YES; 365 | CLANG_WARN_CONSTANT_CONVERSION = YES; 366 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 367 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 368 | CLANG_WARN_EMPTY_BODY = YES; 369 | CLANG_WARN_ENUM_CONVERSION = YES; 370 | CLANG_WARN_INFINITE_RECURSION = YES; 371 | CLANG_WARN_INT_CONVERSION = YES; 372 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 373 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 374 | CLANG_WARN_UNREACHABLE_CODE = YES; 375 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 376 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 377 | COPY_PHASE_STRIP = NO; 378 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 379 | ENABLE_NS_ASSERTIONS = NO; 380 | ENABLE_STRICT_OBJC_MSGSEND = YES; 381 | GCC_C_LANGUAGE_STANDARD = gnu99; 382 | GCC_NO_COMMON_BLOCKS = YES; 383 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 384 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 385 | GCC_WARN_UNDECLARED_SELECTOR = YES; 386 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 387 | GCC_WARN_UNUSED_FUNCTION = YES; 388 | GCC_WARN_UNUSED_VARIABLE = YES; 389 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 390 | MTL_ENABLE_DEBUG_INFO = NO; 391 | SDKROOT = iphoneos; 392 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 393 | VALIDATE_PRODUCT = YES; 394 | }; 395 | name = Release; 396 | }; 397 | C0F7C00A1DFC128600948E16 /* Debug */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 401 | INFOPLIST_FILE = "Flappy Bird/Info.plist"; 402 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 403 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 404 | PRODUCT_BUNDLE_IDENTIFIER = "i-Techsys.com.Flappy-Bird"; 405 | PRODUCT_NAME = "MG Bird"; 406 | SWIFT_VERSION = 3.0; 407 | }; 408 | name = Debug; 409 | }; 410 | C0F7C00B1DFC128600948E16 /* Release */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 414 | INFOPLIST_FILE = "Flappy Bird/Info.plist"; 415 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 416 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 417 | PRODUCT_BUNDLE_IDENTIFIER = "i-Techsys.com.Flappy-Bird"; 418 | PRODUCT_NAME = "MG Bird"; 419 | SWIFT_VERSION = 3.0; 420 | }; 421 | name = Release; 422 | }; 423 | /* End XCBuildConfiguration section */ 424 | 425 | /* Begin XCConfigurationList section */ 426 | C0F7BFEC1DFC128600948E16 /* Build configuration list for PBXProject "Flappy Bird" */ = { 427 | isa = XCConfigurationList; 428 | buildConfigurations = ( 429 | C0F7C0071DFC128600948E16 /* Debug */, 430 | C0F7C0081DFC128600948E16 /* Release */, 431 | ); 432 | defaultConfigurationIsVisible = 0; 433 | defaultConfigurationName = Release; 434 | }; 435 | C0F7C0091DFC128600948E16 /* Build configuration list for PBXNativeTarget "Flappy Bird" */ = { 436 | isa = XCConfigurationList; 437 | buildConfigurations = ( 438 | C0F7C00A1DFC128600948E16 /* Debug */, 439 | C0F7C00B1DFC128600948E16 /* Release */, 440 | ); 441 | defaultConfigurationIsVisible = 0; 442 | defaultConfigurationName = Release; 443 | }; 444 | /* End XCConfigurationList section */ 445 | }; 446 | rootObject = C0F7BFE91DFC128600948E16 /* Project object */; 447 | } 448 | --------------------------------------------------------------------------------