SpriteKit(7) - 音頻和視頻

背景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. 可能有別的細節(jié)問題.暫時列為一個為解決的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)
        }
        
        //添加子彈音樂
        //說明: 這里的做法是創(chuàng)建每一個音效對應一個子彈,好比如一個腳本對應一個NPC一樣.
        //嘗試過: 單獨之創(chuàng)建一個音效,每次點擊都調(diào)用這個,但是有點不完美的地方是,手速太快,當前音效還沒播放完畢,匆忙結(jié)束又從新開始播放一遍,很突兀.
        //思考: 最佳方案應該是單純一個音效對象,每次點擊發(fā)射子彈的時候調(diào)用.
        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次以上,也就是連續(xù)發(fā)射5發(fā)子彈了.那么就等待下一次.
        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
            
            //發(fā)射子彈動作
            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])
            //結(jié)束發(fā)送動作
            let endAction = SKAction.run({
                playerBullet.removeAllActions()
                playerBullet.isHidden = true
                playerBullet.position = self.shipNode.position
            })

            //動作組合
            let fireSequence = SKAction.sequence([shootGroup,endAction])
            playerBullet.run(fireSequence)
            
        }
    }
    
    //判斷如果是已經(jīng)發(fā)射過5發(fā)了,就將子彈數(shù)置為0
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        if currentBullet > 5 {
            currentBullet = 0
        }
    }
}
音效

簡單做了一個飛機發(fā)射子彈的操作,小總結(jié):

  • 每一個子彈對應一個節(jié)點,每一個子彈音效對應一個AVAudioPlayer
  • 注意發(fā)射子彈的邏輯.
  • bgm音樂還有子彈音效可以自己隨便找一個就好,目前只是為了練手,不細致去求素材.
  • 每篇代碼都不多

點擊節(jié)點出發(fā)事件

 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
                }
            }
        }
    }
}
節(jié)點觸摸事件
  • 這里主要是實現(xiàn)觸摸事件的思路.節(jié)點本身沒有提供點擊事件的操作,不像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掉非常低.達不到預覽效果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容