

現在、おみくじのサンプルアプリで勉強をしています。  
サンプルコードを参考にBGMの再生はできたのですが、BGMの切り替え方法がわかりません。  
画面推移を使わず、同一画面のままBGMを切り替えたいです。

どんなコードをどの部分に入れればBGMが切り替え出来ますか？

わかる方いましたら、ご教授よろしくおねがします。  
使用している環境はXcode7 swift2.0です。

ーーGameViewController BGM１を再生ーー

[code]

    import UIKit
    import SpriteKit
    import AVFoundation     //AVFoundationフレームワークをインポートする。
    
    class GameViewController: UIViewController {
    
        var player:AVAudioPlayer?       //BGM を制御するための変数
        var soundManager = SEManager()  //SEManager でインスタンス化した変数
        //BGM再生メソッド
        func play(soundName:String){
            //サウンドファイルを読み込む
            let soundPath = NSBundle.mainBundle().bundlePath.stringByAppendingPathComponent(soundName)
            //読み込んだファイルにパスを付ける
            let url:NSURL? = NSURL.fileURLWithPath(soundPath)
            do {
                //↓playerに読み込んだmp3ファイルへのパスを設定する
                player = try AVAudioPlayer(contentsOfURL:url!)
            } catch _ {
                player = nil
            }
            player?.numberOfLoops = -1      //BGMを無限にループさせる
            player?.prepareToPlay()         //音声を即時再生させる。
            player?.play()                  //音を再生する
        }
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            //bgm
            // Do any additional setup after loading the view, typically from a nib.
            //playメソッドの呼び出し。引数はファイル名。
            play("bgm1.mp3")
    
    
            let scene = GameScene(size:CGSize(width: 750, height: 1334))
            let skView = self.view as! SKView
            scene.scaleMode = .AspectFit
            skView.presentScene(scene)
        }
    
        override func shouldAutorotate() -> Bool {
            return true
        }
    
        override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
            if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
                return UIInterfaceOrientationMask.AllButUpsideDown
            } else {
                return UIInterfaceOrientationMask.All
            }
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Release any cached data, images, etc that aren't in use.
        }
    
        override func prefersStatusBarHidden() -> Bool {
            return true
        }
    }
    
[/code]

・・・・・GameScene.swift

[code]

    import SpriteKit
    import AVFoundation
    
    class GameScene: SKScene {
        // イラスト用スプライトを用意する
        let mySprite = SKSpriteNode(imageNamed: "omikuji.png")
        // ボタン用スプライトを用意する
        let btnSprite = SKSpriteNode(imageNamed: "button.png")
        // おみくじ結果用ラベルを用意する
        let myLabel = SKLabelNode(fontNamed: "Verdana-bold")
    
        override func didMoveToView(view: SKView) {
    
    
    
            // 背景色をつける
            self.backgroundColor = SKColor.whiteColor()
            // イラストを表示する
            mySprite.position = CGPoint(x: 375, y: 900)
            addChild(mySprite)
            // ボタンを表示する
            btnSprite.position = CGPoint(x:375, y:200)
            self.addChild(btnSprite)
            // おみくじ結果用ラベルを表示する
            myLabel.text = "???"
            myLabel.fontSize = 65
            myLabel.fontColor = SKColor.blackColor()
            myLabel.position = CGPoint(x:375, y:500)
            self.addChild(myLabel)
        }
        // タッチしたときの処理
        override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
            for touch: AnyObject in touches {
                // タッチされた位置にあるものを調べて
                let location = touch.locationInNode(self)
                let touchNode = self.nodeAtPoint(location)
                // もし、ボタンなら
                if touchNode == btnSprite {
    
                    //効果音がなった時、BGMは停止しない
    
    
                    // 効果音データの作成.
                    let mySoundAction: SKAction = SKAction.playSoundFileNamed("hit.wav", waitForCompletion: true)
                    // 再生アクション.
                    self.runAction(mySoundAction);
    
                    // ???と表示してから、おみくじを振る
                    myLabel.text = "???"
                    shakeOmikuji()
                }
            }
        }
        // おみくじを振る処理
        func shakeOmikuji() {
    
            //BGMサンプル１再生停止
            //ここでBGMをサンプル２に切り替えたい
    
    
            // 【おみくじを振るアクションをつける】
            // おみくじを少し右に傾けるアクション
            let action1 = SKAction.rotateToAngle(-0.3, duration: 0.2)
            // おみくじを少し左に傾けるアクション
            let action2 = SKAction.rotateToAngle( 0.3, duration: 0.2)
            // おみくじをひっくり返すアクション
            let action3 = SKAction.rotateToAngle( 3.14, duration: 0.2)
            // action1,action2,action3を指定した順番に行う
            let actionS = SKAction.sequence(
                [action1, action2, action1, action2, action1, action3])
    
            // おみくじに「左右に振ってひっくり返すアクション」をつけて、最後にkekkaを実行する
            mySprite.runAction(actionS, completion: showOmikuji)
        }
        // 結果を表示する処理
        func showOmikuji() {
            var omikuji = ["大吉","中吉","吉","凶"]
            let r = Int(arc4random_uniform(4))
            myLabel.text = omikuji[r]
        }
    
        override func update(currentTime: CFTimeInterval) {
        }
    }
    
[/code]


CC BY-SA 3.0
2015-07-06T23:58:45.427
12101
2015-07-07T16:44:59.093
2015-07-07T06:27:49.433
7362
10353
question
swift
XcodeでAVFoundationを使いBGMを切り替える方法を教えてください


どんなきっかけでBGMの変更がしたいですか？  
それにより追加するコードが変わります。  
例えば、ボタンのタップでBGMが変更される。などです。  
単純に音楽を変えたい場合は、AVAudioPlayerをstop()して、再度パス指定をしてprepareToPlay()をすれば変更できます。


CC BY-SA 3.0
2015-07-07T06:43:06.970
12111
2015-07-07T06:43:06.970
8772
12101
answer


以下、一本指タップで、BGMが変わり、二本指（以上）タップで、BGM再生を止めたり再開するプログラムです。

[code]

    import UIKit
    import SpriteKit
    import AVFoundation
    
    class GameScene: SKScene {
    
        private var southernURL: NSURL!
        private var happyURL: NSURL!
        var currentBGM: AVAudioPlayer!
    
        override init(size: CGSize) {
            super.init(size: size)
    
            self.backgroundColor = UIColor.yellowColor()
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override func didMoveToView(view: SKView) {
            super.didMoveToView(view)
    
            let bndl = NSBundle.mainBundle()
            southernURL = bndl.URLForResource("southern", withExtension: "m4a")
            happyURL = bndl.URLForResource("happy", withExtension: "m4a")
    
            currentBGM = AVAudioPlayer(contentsOfURL: southernURL, error: nil)
            currentBGM.numberOfLoops = -1
            currentBGM.play()
        }
    
        override func willMoveFromView(view: SKView) {
            super.willMoveFromView(view)
    
            if currentBGM.playing == true {
                currentBGM.stop()
            }
        }
    
        override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
            if touches.count < 2 { // 一本指タップなら
                changeBGM()
            } else { // 二本指以上なら
                pauseBGM()
            }
        }
    
        func changeBGM() {
            if currentBGM.playing {
                currentBGM.stop()
                if currentBGM.url == southernURL {
                    currentBGM = AVAudioPlayer(contentsOfURL: happyURL, error: nil)
                } else {
                    currentBGM = AVAudioPlayer(contentsOfURL: southernURL, error: nil)
                }
                currentBGM.numberOfLoops = -1
                currentBGM.play()
            }
        }
    
        func pauseBGM() {
            if currentBGM.playing {
                currentBGM.pause() // pause()なら、サウンドファイルとのつながりが切れない。そして再開時、停止したところから始まる。
            } else {
                currentBGM.play()
            }
        }
    
    }
    
[/code]

確実にnilにならないことが保証されているケースでは、インスタンス変数をOptional（?）ではなく、Inplicitly Unwrapped
Optional（!）にすることができます。なお、「確実にnilにならない保証」をするのは、プログラマ自身です。

`NSBundle`の`URLForResource()`などは、リソースファイルの取得に失敗すると、`nil`を返します。なので、swift2.0の例外処理を使う必要はありません。今回は、「プログラマの責任」で、まちがいなくサウンドファイルがある前提で、Inplicitly
Unwrapped Optional（!）としましたが、サウンドファイル取得を失敗した時のケースを考慮するなら、Optional
Binding等を使って、変数の内容が`nil`かそうでないかで条件分岐してください。

再生開始時のタイムラグ（遅延）を気にしなければ、`prepareToPlay()`メソッドは呼ぶ必要はありません。


CC BY-SA 3.0
2015-07-07T12:05:51.467
12122
2015-07-07T16:44:59.093
2015-07-07T16:44:59.093
7362
7362
12101
answer