import UIKit
import AudioToolbox   //播放音效
import AVFoundation //播放音乐
let SCREEN_SIZE = UIScreen.main.bounds
class ViewController: UIViewController, CAAnimationDelegate {

    var timerBg:Timer?
    var timerTube:Timer?
    var bird:UIImageView!
    var cloud:UIImageView!
    var cloudAnimation:CAKeyframeAnimation!
    var timerBird:Timer?
    var t:Float = 0.0
    var isFlyUpward = false
    var bgMusic:AVAudioPlayer!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.creatBackgroundView()
        self.creatTube()
        self.creatTimer()
        self.creatBird()
        self.creatCloud()
        self.playOrPauseBgMusic()
    }
    
    func creatBackgroundView(){
        //创建城市背景
        let imageCity = UIImage(named: "bg-city.png")
        let viewCity = UIImageView(image: imageCity)
        let viewCity2 = UIImageView(image: imageCity)
        viewCity.frame = CGRect(x: 0, y: 0, width: SCREEN_SIZE.width, height: SCREEN_SIZE.height)
        viewCity2.frame = CGRect(x: SCREEN_SIZE.width, y: 0, width: SCREEN_SIZE.width + 1, height: SCREEN_SIZE.height)
        self.view.addSubview(viewCity)
        self.view.addSubview(viewCity2)
        viewCity.tag = 101
        viewCity2.tag = 102
        //创建大地背景
        let viewGround = UIImageView(frame: CGRect(x: 0, y: SCREEN_SIZE.height - 100, width: SCREEN_SIZE.width, height: 100))
        let viewGround2 = UIImageView(frame: CGRect(x: SCREEN_SIZE.width, y: SCREEN_SIZE.height - 100, width: SCREEN_SIZE.width + 2, height: 100))
        let imageGround = UIImage(named: "bg-ground.png")
        viewGround.image = imageGround
        viewGround2.image = imageGround
        self.view.addSubview(viewGround)
        self.view.addSubview(viewGround2)
        viewGround.tag = 103
        viewGround2.tag = 104
    }
    
    func creatTube(){
        let imageTubeUp = UIImage(named: "tube-up.png")
        let imageTubeDown = UIImage(named: "tube-down.png")
        //第一对水管
        let viewTubePairOneUp = UIImageView(frame: CGRect(x: 0, y: -SCREEN_SIZE.height, width: 54, height: SCREEN_SIZE.height))
        let viewTubePairOneDown = UIImageView(frame: CGRect(x: 0, y: SCREEN_SIZE.height, width: 54, height: SCREEN_SIZE.height))
        viewTubePairOneUp.image = imageTubeUp
        viewTubePairOneDown.image = imageTubeDown
        viewTubePairOneUp.tag = 201
        viewTubePairOneDown.tag = 202
        //第二对水管
        let viewTubePairTwoUp = UIImageView(frame: CGRect(x: SCREEN_SIZE.width/2, y: -SCREEN_SIZE.height, width: 54, height: SCREEN_SIZE.height))
        let viewTubePairTwoDown = UIImageView(frame: CGRect(x: SCREEN_SIZE.width/2, y: SCREEN_SIZE.height, width: 54, height: SCREEN_SIZE.height))
        viewTubePairTwoUp.image = imageTubeUp
        viewTubePairTwoDown.image = imageTubeDown
        viewTubePairTwoUp.tag = 203
        viewTubePairTwoDown.tag = 204
        //第三对水管
        let viewTubePairThreeUp = UIImageView(frame: CGRect(x: SCREEN_SIZE.width, y: -SCREEN_SIZE.height, width: 54, height: SCREEN_SIZE.height))
        let viewTubePairThreeDown = UIImageView(frame: CGRect(x: SCREEN_SIZE.width, y: SCREEN_SIZE.height, width: 54, height: SCREEN_SIZE.height))
        viewTubePairThreeUp.image = imageTubeUp
        viewTubePairThreeDown.image = imageTubeDown
        viewTubePairThreeUp.tag = 205
        viewTubePairThreeDown.tag = 206
        //添加水管到到第一个大地背景视图下方
        let viewGroud = self.view.viewWithTag(103)!
        self.view.insertSubview(viewTubePairOneUp, belowSubview: viewGroud)
        self.view.insertSubview(viewTubePairOneDown, belowSubview: viewGroud)
        self.view.insertSubview(viewTubePairTwoUp, belowSubview: viewGroud)
        self.view.insertSubview(viewTubePairTwoDown, belowSubview: viewGroud)
        self.view.insertSubview(viewTubePairThreeUp, belowSubview: viewGroud)
        self.view.insertSubview(viewTubePairThreeDown, belowSubview: viewGroud)
    }
    
    func creatTimer(){
        timerBg = Timer.scheduledTimer(timeInterval: 0.02, target: self, selector: #selector(self.backgroundMove), userInfo: nil, repeats: true)
        timerTube = Timer.scheduledTimer(timeInterval: 0.02, target: self, selector: #selector(self.tubeMove), userInfo: nil, repeats: true)
        timerBird = Timer.scheduledTimer(timeInterval: 0.02, target: self, selector: #selector(self.birdMove), userInfo: nil, repeats: true)
    }
    
    @objc func backgroundMove(){
        let viewCity = self.view.viewWithTag(101)
        let viewCity2 = self.view.viewWithTag(102)
        let viewGround = self.view.viewWithTag(103)
        let viewGround2 = self.view.viewWithTag(104)
        if (viewCity?.frame.origin.x)! > -SCREEN_SIZE.width{
            viewCity?.frame.origin.x -= 1
        }else{
            viewCity?.frame.origin.x=SCREEN_SIZE.width
        }
        if (viewCity2?.frame.origin.x)! > -SCREEN_SIZE.width{
            viewCity2?.frame.origin.x -= 1
        }else{
            viewCity2?.frame.origin.x = SCREEN_SIZE.width
        }
        if (viewGround?.frame.origin.x)! > -SCREEN_SIZE.width{
            viewGround?.frame.origin.x -= 2
        }else{
            viewGround?.frame.origin.x = SCREEN_SIZE.width
        }
        if (viewGround2?.frame.origin.x)! > -SCREEN_SIZE.width{
            viewGround2?.frame.origin.x -= 2
        }else{
            viewGround2?.frame.origin.x = SCREEN_SIZE.width
        }
    }
    
    @objc func tubeMove(){
        //通过间隔Tag取值，获取图像视图
        for i in stride(from: 201, to: 206, by: 2) {
            //水管移出左边屏幕一半的距离时候就添加到屏幕最右边
            if self.view.viewWithTag(i)!.frame.origin.x > -SCREEN_SIZE.width/2 {
                self.view.viewWithTag(i)?.frame.origin.x -= 2
                self.view.viewWithTag(i + 1)?.frame.origin.x -= 2
            }else{
                self.view.viewWithTag(i)?.frame.origin.x = SCREEN_SIZE.width
                self.view.viewWithTag(i + 1)?.frame.origin.x = SCREEN_SIZE.width
                //调整水管y轴坐标值，即高度
                self.getPosition(viewUp: self.view.viewWithTag(i) as! UIImageView, viewDown: self.view.viewWithTag(i + 1) as! UIImageView)
            }
        }
    }
    
    func getPosition(viewUp: UIImageView, viewDown: UIImageView){
        //产生随机数，范围[30,330)，范围越大小鸟越不容易通过
        let height = arc4random()%300 + 30
        //设置上下水管的y轴坐标值
        viewUp.frame.origin.y = (CGFloat)(-SCREEN_SIZE.height)+(CGFloat)(height)
        //上下水管之间的间隙设置为150,间隙越大小鸟越容易通过
        viewDown.frame.origin.y = (CGFloat)(height) + 150.0
    }
    
    func creatBird(){
        var images = [UIImage]()
        for i in 1...3 {  //3张鸟动作图片
            let image = UIImage(named: NSString(format: "bird%d.png", i) as String)
            images.append(image!)
        }
        bird = UIImageView(frame: CGRect(x: 50, y: 200, width: 35, height: 35))
        bird.animationImages = images
        bird.animationRepeatCount = 0
        bird.animationDuration = 0.3
        bird.startAnimating()
        self.view.addSubview(bird)
    }
    
    func creatCloud(){
        cloud = UIImageView(frame: CGRect(x: 450, y: 60, width: 80, height: 30))
        cloud.image = UIImage(named: "cloud.png")
        let viewTube = self.view.viewWithTag(201)!
        self.view.insertSubview(cloud, belowSubview: viewTube)
        //使用便利构造器创建动画实例
        cloudAnimation = CAKeyframeAnimation(keyPath: "position")
        //云朵视图矩形的中心点
        let point1 = CGPoint(x: 450, y: 60)
        let point2 = CGPoint(x: 300, y: 100)
        let point3 = CGPoint(x: 150, y: 60)
        let point4 = CGPoint(x: -50, y: 150)
        cloudAnimation.values = [NSValue(cgPoint: point1), NSValue(cgPoint: point2),  NSValue(cgPoint: point3), NSValue(cgPoint: point4)]
        cloudAnimation.keyTimes = [NSNumber(value: 0.0), NSNumber(value: 0.2),NSNumber(value: 0.8), NSNumber(value: 1.0)]
        cloudAnimation.duration = 5.0
        //添加CAAnimationDelegate协议代理来获得结束事件的回调
        cloudAnimation.delegate = self
        //开始动画
        cloud.layer.add(cloudAnimation, forKey: "cloud")
    }
    
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool){
        if flag == true {
            cloud.layer.add(cloudAnimation, forKey: "cloud")
        }
    }

    @objc func birdMove(){
        if isFlyUpward == false {
            //自由落体运动
            if bird.frame.origin.y < SCREEN_SIZE.height - 140 {
                bird.frame.origin.y += (CGFloat)(9.8*(t*t/2) - 9.8*(t-0.02)*(t-0.02)/2)*30
                t += 0.02
            }
        }else{
            //竖直上抛运动
            if t < 0.2 {
                bird.frame.origin.y -= (CGFloat)((10.0*t-9.8*t*t/2) - (10.0*(t-0.02)-9.8*(t-0.02)*(t-0.02)/2))*30
                t += 0.02
            }else{
                //超出10个节拍后，不管是否到达最高点，都直接转为自由落体运动
                isFlyUpward = false
            }
        }
        self.hitDetectionAndGameOver()
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?){
        //若小鸟动画进行中表示游戏没有结束
        if bird.isAnimating == true {
            //屏幕触摸动作后，小鸟改为竖直上抛运动
            isFlyUpward = true
            t = 0
            self.playScreenTouchSound()
        }else{
            //重新加载游戏
            self.reloadGame()
        }
    }
    
    func playScreenTouchSound(){
        var mySoundId:SystemSoundID = 0
        //获得文件目录
        let myPath = Bundle.main.path(forResource: "sound-touch", ofType: "wav")
        //文件目录path转换为URL形式，更具有普遍性
        let mySoundURL = URL(fileURLWithPath: myPath!)
        //生成音效的SoundID
        AudioServicesCreateSystemSoundID(mySoundURL as CFURL, &mySoundId)
        //通过SoundID播放结束，结束后调用闭包一次
        AudioServicesPlaySystemSoundWithCompletion(mySoundId){ () -> Void in
            //print("点击了屏幕!", mySoundId)
            //单次播放音效
            //AudioServicesPlaySystemSoundWithCompletion(mySoundId, nil)
        }
    }
        
    func playOrPauseBgMusic(){
        if bgMusic == nil {
            //只会进入这里一次
            let myPath = Bundle.main.path(forResource: "bg-music", ofType: "mp3")
            let mySoundURL = URL(fileURLWithPath: myPath!)
            do{
                try bgMusic = AVAudioPlayer(contentsOf: mySoundURL)
                //设置音量最大，范围0.0-1.0
                bgMusic.volume = 1.0
                //设置-1表示无限循环，0表示1次，1表示2次
                bgMusic.numberOfLoops = -1
                //若要获得播放结束等状态信息，可以设置代理
                //bgMusic.delegate = self
            } catch{
                print("音乐配置出错",error)
            }
        }
        //切换音乐播放和暂停
        if bgMusic.isPlaying {
            bgMusic.pause()
        }
        else{
            bgMusic.play()
        }
    }
    
    func hitDetectionAndGameOver(){
        for i in 201...206 {
            //若小鸟矩形区域与任意水管矩形区域相交，就认为游戏结束
            if bird.frame.intersects(self.view.viewWithTag(i)!.frame) {
                //碰撞发生，就停止相关运动
                timerBg!.fireDate = Date.distantFuture as Date   //停止城市和大地背景运动
                timerTube!.fireDate = Date.distantFuture as Date   //停止水管运动
                timerBird!.fireDate = Date.distantFuture as Date   //停止小鸟运动
                bird.stopAnimating()  //停止小鸟动画
                cloud.layer.removeAnimation(forKey: "cloud")   //停止云朵漂浮
                self.playOrPauseBgMusic()   //关闭背景音乐
                //播放碰撞水管音效
                var mySoundId:SystemSoundID = 0
                let myPath = Bundle.main.path(forResource: "sound-hit", ofType: "wav")
                AudioServicesCreateSystemSoundID(URL(fileURLWithPath: myPath!) as CFURL, &mySoundId)
                AudioServicesPlaySystemSoundWithCompletion(mySoundId, nil)
                //显示游戏结束横条
                let showGameOverBanner = UIImageView(frame: CGRect(x: 30, y: 100, width: SCREEN_SIZE.width-60, height: 60))
                showGameOverBanner.image = UIImage(named: "gameover.png")
                showGameOverBanner.tag = 301
                self.view.addSubview(showGameOverBanner)
            }
        }
    }

    func reloadGame(){
        //水管从初始位置开始
        for i in stride(from: 201, to: 206, by: 2) {
            self.view.viewWithTag(i)?.frame = CGRect(x: SCREEN_SIZE.width*(CGFloat(i)-201)/4, y: -SCREEN_SIZE.height, width: 54, height: SCREEN_SIZE.height)
            self.view.viewWithTag(i+1)?.frame = CGRect(x: SCREEN_SIZE.width*(CGFloat(i)-201)/4, y: SCREEN_SIZE.height, width: 54, height: SCREEN_SIZE.height)
        }
        //小鸟从初始位置开始开启动画
        bird.frame = CGRect(x: 50, y: 200, width: 35, height: 35)
        bird.startAnimating()
        //恢复云朵动画
        cloud.layer.add(cloudAnimation, forKey: "cloud")
        //开启背景音乐
        self.playOrPauseBgMusic()
        //移走gameover横幅
        let showGameOverBanner = self.view.viewWithTag(301)
        showGameOverBanner?.removeFromSuperview()
        //重新开始计时
        t = 0
        //开启定时器
        timerBg!.fireDate = Date.distantPast as Date
        timerTube!.fireDate = Date.distantPast as Date
        timerBird!.fireDate = Date.distantPast as Date
    }
    
}
用swiftui改写