美文网首页ARKit&SceneKit入门
SpriteKit(7) - 音频和视频

SpriteKit(7) - 音频和视频

作者: li_礼光 | 来源:发表于2017-07-31 19:03 被阅读60次

    背景BGM

    import SpriteKit
    import GameplayKit
    import AVFoundation
    
    class GameAVFoundation: SKScene {
        var audioPlayer : AVAudioPlayer = {
            var player : AVAudioPlayer?
            let mp3Path = Bundle.main.path(forResource: "bgm", ofType: "mp3")   //bgm自己放一首进去就好
            let pathURL = NSURL.fileURL(withPath: mp3Path!)
            try? player = AVAudioPlayer(contentsOf: pathURL)
            return player!
        }()
        var timeLabel : SKLabelNode!
        
        var firstPoint : CGPoint!
        var lastPoint : CGPoint!
        
        var currentVolume : Float = 1.0
        var currentVolumeLabel : SKLabelNode!
        
        override func didMove(to view: SKView) {
            self.size = UIScreen.main.bounds.size
            let label = SKLabelNode()
            label.text = "点击屏幕,开始播放音乐"
            label.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
            label.fontSize = 64
            label.fontName = "Baby-blocks"
            self.addChild(label)
            
            timeLabel = SKLabelNode()
            timeLabel.text = "当前播放了\(audioPlayer.currentTime)"
            timeLabel.position = CGPoint(x: self.frame.midX, y: self.frame.minY + 80)
            timeLabel.fontSize = 20
            timeLabel.fontName = "Baby-blocks"
            timeLabel.fontColor = UIColor.white
            self.addChild(timeLabel)
            
            currentVolumeLabel = SKLabelNode()
            currentVolumeLabel.text = ""
            currentVolumeLabel.position = CGPoint(x: self.frame.midX, y: self.frame.minY + 120)
            currentVolumeLabel.fontSize = 30
            currentVolumeLabel.fontName = "Baby-blocks"
            currentVolumeLabel.fontColor = UIColor.white
            self.addChild(currentVolumeLabel)
            
            
            let tap = UITapGestureRecognizer(target: self, action: #selector(GameAVFoundation.playMusic))
            self.view?.addGestureRecognizer(tap)
            
        }
        
        @objc func playMusic() {
            audioPlayer.numberOfLoops = 5
            audioPlayer.play()
        }
        
        override func update(_ currentTime: TimeInterval) {
            timeLabel.text = String(format: "当前播放了%.0f秒", audioPlayer.currentTime)
        }
        
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            //获取当前点击的点的坐标
            let touchs = touches as NSSet
            let touch : AnyObject = touchs.anyObject() as AnyObject
            firstPoint = touch.location(in: self)
        }
        
        override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
            //获取当前点击的点的坐标
            let touchs = touches as NSSet
            let touch : AnyObject = touchs.anyObject() as AnyObject
            lastPoint = touch.location(in: self)
            let dy = lastPoint.y - firstPoint.y
            
            //简单做一个上下滑增加,和减低音乐的操作  
            if dy <= -100 {
                self.audioPlayer.volume = 0
            }else  if dy < 0 {
                if Float(dy * 0.01) + self.currentVolume <= 0 {
                    self.audioPlayer.volume = 0
                } else {
                    self.audioPlayer.volume = Float(dy * 0.01) + self.currentVolume;
                }
            }else  if dy < 100 {
                if Float(dy * 0.01) + self.currentVolume >= 1 {
                    self.audioPlayer.volume = 1
                } else {
                    self.audioPlayer.volume = Float(dy * 0.01) + self.currentVolume;
                }
            } else {
                self.audioPlayer.volume = 1
            }
            currentVolumeLabel.text = String(format: "当前音量大小 : %.0f", self.currentVolume * 100)
        }
    
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
            self.currentVolume = self.audioPlayer.volume
        }
    }
    
    效果

    PS : 这里本来打算做一个,随着上下滑动屏幕,然后达到音量的增减,同时,同步的显示当前的音量大小,但是这里面的currentVolumeLabel.text不会马上的同步刷新,打印了当前线程是main. 可能有别的细节问题.暂时列为一个为解决的bug. 因为 : 先不在这里钻牛角尖.耗时间有点不太好.

    音效.

    import SpriteKit
    import GameplayKit
    import AVFoundation
    
    class GameSoundEffect: SKScene {
        
        let shipNode : SKSpriteNode = SKSpriteNode(imageNamed: "ship")
        var bullets : NSMutableArray =   NSMutableArray(capacity: 5)
        var bulletSound : NSMutableArray =   NSMutableArray(capacity: 5)
        var currentBullet :Int = 0
        
        var bgmPlayer : AVAudioPlayer = {
            var player : AVAudioPlayer?
            let mp3Path = Bundle.main.path(forResource: "backgroundMusic", ofType: "mp3")   //bgm自己放一首进去就好
            let pathURL = NSURL.fileURL(withPath: mp3Path!)
            do {
                try player = AVAudioPlayer(contentsOf: pathURL)
            } catch {
                print(error)
            }
            return player!
        }()
        
        override func didMove(to view: SKView) {
            self.size = UIScreen.main.bounds.size
            //添加飞机
            shipNode.position = CGPoint(x: self.frame.midX, y: 50)
            shipNode.size = CGSize(width: 100, height: 100)
            self.addChild(shipNode)
            //添加子弹
            for _ in 0...5 {
                let bulletNode = SKSpriteNode(imageNamed: "bullet")
                bulletNode.position = self.shipNode.position
                bulletNode.isHidden = true
                bullets.add(bulletNode)
                self.addChild(bulletNode)
            }
            
            //添加子弹音乐
            //说明: 这里的做法是创建每一个音效对应一个子弹,好比如一个脚本对应一个NPC一样.
            //尝试过: 单独之创建一个音效,每次点击都调用这个,但是有点不完美的地方是,手速太快,当前音效还没播放完毕,匆忙结束又从新开始播放一遍,很突兀.
            //思考: 最佳方案应该是单纯一个音效对象,每次点击发射子弹的时候调用.
            for _ in 0...5 {
                var player : AVAudioPlayer!
                let mp3Path = Bundle.main.path(forResource: "sound", ofType: "caf")   //bgm自己放一首进去就好
                let pathURL = NSURL.fileURL(withPath: mp3Path!)
                do {
                    try player = AVAudioPlayer(contentsOf: pathURL)
                } catch {
                    print(error)
                }
                bulletSound.add(player)
            }
                
            //添加背景音乐
            bgmPlayer.numberOfLoops = Int(INT_MAX)
            bgmPlayer.play()
        }
        
        
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            //判断touch.tapCount > 5如果快速点击超过5次以上,也就是连续发射5发子弹了.那么就等待下一次.
            for touch in touches {
                if touch.tapCount > 5 || currentBullet > self.bullets.count {
                    return 
                }
                //先获取子弹对象
                let playerBullet : SKSpriteNode = self.bullets.object(at: currentBullet) as! SKSpriteNode
                let playerSound : AVAudioPlayer = self.bulletSound.object(at: currentBullet) as! AVAudioPlayer
                currentBullet += 1
                
                playerBullet.position = self.shipNode.position
                playerBullet.isHidden = false
                
                //发射子弹动作
                let fireAction = SKAction.move(to: CGPoint(x: self.frame.midX, y: self.frame.size.height), duration: 1)
                let shootAction = SKAction.run({
                    playerSound.play()
                })
                
                let shootGroup = SKAction.group([fireAction,shootAction])
                //结束发送动作
                let endAction = SKAction.run({
                    playerBullet.removeAllActions()
                    playerBullet.isHidden = true
                    playerBullet.position = self.shipNode.position
                })
    
                //动作组合
                let fireSequence = SKAction.sequence([shootGroup,endAction])
                playerBullet.run(fireSequence)
                
            }
        }
        
        //判断如果是已经发射过5发了,就将子弹数置为0
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
            if currentBullet > 5 {
                currentBullet = 0
            }
        }
    }
    
    音效

    简单做了一个飞机发射子弹的操作,小总结:

    • 每一个子弹对应一个节点,每一个子弹音效对应一个AVAudioPlayer
    • 注意发射子弹的逻辑.
    • bgm音乐还有子弹音效可以自己随便找一个就好,目前只是为了练手,不细致去求素材.
    • 每篇代码都不多

    点击节点出发事件

     import SpriteKit
    import GameplayKit
    import AVFoundation
    
    class GameNodeSound: SKScene {
        
        var musicArr : NSMutableArray!
        
        override func didMove(to view: SKView) {
            self.size = UIScreen.main.bounds.size
            labelNode(position: CGPoint(x: self.frame.midX, y: self.frame.midY + 100), title: "钢琴")
            labelNode(position: CGPoint(x: self.frame.midX - 300, y: self.frame.midY), title: "1")
            labelNode(position: CGPoint(x: self.frame.midX - 200, y: self.frame.midY), title: "2")
            labelNode(position: CGPoint(x: self.frame.midX - 100, y: self.frame.midY), title: "3")
            labelNode(position: CGPoint(x: self.frame.midX + 0  , y: self.frame.midY), title: "4")
            labelNode(position: CGPoint(x: self.frame.midX + 100, y: self.frame.midY), title: "5")
            labelNode(position: CGPoint(x: self.frame.midX + 200, y: self.frame.midY), title: "6")
            labelNode(position: CGPoint(x: self.frame.midX + 300, y: self.frame.midY), title: "7")
            
            musicArr = NSMutableArray(capacity: 7)
            for i in 1...7 {
                let action = SKAction.playSoundFileNamed("\(i).mp3", waitForCompletion: true)
                self.musicArr.add(action)
            }
    
        }
        
        func labelNode(position : CGPoint,title : String) {
            let label = SKLabelNode()
            label.text = title
            label.name = title
            label.position = position
            label.fontSize = 80
            label.fontColor = UIColor.white
            label.fontName = "Baby-blocks"
            self.addChild(label)
        }
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            for touch in touches {
                let point = touch.location(in: self)
                for node in nodes(at: point) {
                    guard let name = node.name else {
                        return
                    }
                    switch name {
                    case "1": node.run(self.musicArr[0] as! SKAction); break
                    case "2": node.run(self.musicArr[1] as! SKAction); break
                    case "3": node.run(self.musicArr[2] as! SKAction); break
                    case "4": node.run(self.musicArr[3] as! SKAction); break
                    case "5": node.run(self.musicArr[4] as! SKAction); break
                    case "6": node.run(self.musicArr[5] as! SKAction); break
                    case "7": node.run(self.musicArr[6] as! SKAction); break
                    default:break
                    }
                }
            }
        }
    }
    
    节点触摸事件
    • 这里主要是实现触摸事件的思路.节点本身没有提供点击事件的操作,不像UIButton,只能通过对应的手势点击屏幕去找去判断.
    • 音频资源可以自己随便找.这个无所谓的
    • 缺点 : 性能不好

    视频

    import SpriteKit
    import GameplayKit
    import AVFoundation
    
    class GameVideo: SKScene {
        
        var videoNode : SKVideoNode!
        override func didMove(to view: SKView) {
            self.size = UIScreen.main.bounds.size
            let videoPath = Bundle.main.path(forResource: "cs", ofType: "mp4")
            let fileURL = URL(fileURLWithPath: videoPath!)
            let player = AVPlayer(url: fileURL)
            videoNode = SKVideoNode(avPlayer: player)
            videoNode.size = UIScreen.main.bounds.size
            videoNode.position = CGPoint.zero
            videoNode.anchorPoint = CGPoint.zero
            self.addChild(videoNode)
        }
        
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            videoNode.play()
        }
    }
    

    PS : 视频播放用真机去操作.模拟器播放fps掉非常低.达不到预览效果

    相关文章

      网友评论

        本文标题:SpriteKit(7) - 音频和视频

        本文链接:https://www.haomeiwen.com/subject/mkerlxtx.html