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. 可能有别的细节问题.暂时列为一个为解决的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掉非常低.达不到预览效果

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容