質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.60%

  • Swift

    7041questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Xcode

    4000questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

前画面から垂れ流しているBGMを画面遷移と同時に停止させたい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 344

mokoporon

score 16

しっかりとまとめられず、質問が長文となっている事、ご容赦ください。

現在、単純な二択クイズアプリを制作しています。複数のページをセグエで接続しており、「タイトル画面」・「クイズ画面」・間違いを選んだ場合の「残念、タイトルに戻る画面」から構成されています。

「タイトル画面のBGM」と「ゲーム中BGM」が用意されており、問題に間違えるまでは「ゲーム中BGM」を垂れ流しにしたいと考えています。
間違えた時点で「ブブー」というSEとともにhoge.stop()でBGMを止め、タイトル画面に戻った際のBGM重複を防いでいます。

しかし、この方法では後述の問題が発生します。

タイトル画面(ViewContoroller)では、ViewDidLoad内に

//BGMに関する部分以外は省略。
import UIKit
import AVFoundation

var player:AVAudioPlayer?

override func viewDidLoad() {
        super.viewDidLoad()

        let url = Bundle.main.bundleURL.appendingPathComponent("titlemus.mp3")
        do {
            try player = AVAudioPlayer(contentsOf: url)
        } catch {
            print("Error")
        }
        player!.play()
        player!.numberOfLoops = -1
    }


と書いてあり、アプリ起動と同時にBGMが再生されます(ちなみに、オプショナルの知識もまだまだしっかりとは理解しておらず、player!.play() でも player?.play()でも再生されたので、とりあえず ! で記載をしています)。

タイトル画面のGame Startを押すと、画面遷移とともにBGMが切り替わります。(FirstViewControllerへ遷移)

import UIKit
import AVFoundation

class FristViewController: UIViewController {

    //ゲーム中BGM
    var player2:AVAudioPlayer?
    //正解の場合のSE
    var ongaku1:AVAudioPlayer?
    //間違いの場合のSE
    var music1:AVAudioPlayer?

    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

       //画面遷移をした際に切り替わるBGMを設定。(ゲーム中のBGM)

        let url = Bundle.main.bundleURL.appendingPathComponent("gameplay.mp3")
        do {
            try player2 = AVAudioPlayer(contentsOf: url)
        } catch {
            print("Error")
        }
        player2!.play()
        player2!.numberOfLoops = -1
        player2!.volume = 0.6

        self.label.text = "問題文1"
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    /*seikai1ボタンはセグエで接続されており、タップすると次の問題画面に切り替わる。
         その際に「ピンポン(seikai.mp3)」という音が鳴る。*/
    @IBAction func seikai1(_ sender: Any) {
        let t1 = Bundle.main.bundleURL.appendingPathComponent("seikai.mp3")
        do {
            try ongaku1 = AVAudioPlayer(contentsOf: t1)
        } catch {
            print("Error")
        }
        ongaku1!.play()

    }

    /*machigai1ボタンはセグエで接続されており、タップすると残念画面に切り替わる。
         その際に「ブブー(machigai.mp3)」という音が鳴る。*/
    @IBAction func machigai1(_ sender: Any) {
        let f1 = Bundle.main.bundleURL.appendingPathComponent("machigai.mp3")
        do {
            try music1 = AVAudioPlayer(contentsOf: f1)
        } catch {
            print("Error")
        }
        music1!.play()

        //ここでplayer2(ゲーム中BGM)を止めることで、音楽の重複を防いでいる。
        player2!.stop()
    }

}

という具合にしています。この方法ですと、前述のとおり第一問(FirstViewController)で間違えた際には、ゲーム中BGM、タイトルBGMが被らずにタイトルに戻ることができます。しかし、ここで正解を選んだ場合、SecondViewController画面へと遷移をします。問題なのはここからで、二問目以降で間違えた場合、ゲーム中BGMとタイトルBGMが重複してしまいます。

import UIKit
import AVFoundation

class SecondViewController: UIViewController {

    var ongaku2 : AVAudioPlayer?
    var music2 : AVAudioPlayer?

//省略

    @IBAction func seikai2(_ sender: Any) {
        let t2 = Bundle.main.bundleURL.appendingPathComponent("seikai.mp3")
        do {
            try ongaku2 = AVAudioPlayer(contentsOf : t2)
        } catch {
            print("Error")
        }
        ongaku2!.play()
    }

    @IBAction func machigai2(_ sender: Any) {
        let f2 = Bundle.main.bundleURL.appendingPathComponent("machigai.mp3")
        do {
            try music2 = AVAudioPlayer(contentsOf : f2)
        } catch {
            print("Error")
        }
        music2!.play()

        //理想としては、ここでBGMを止めたいが...(他画面では前画面のコードは引き継がれずエラー)
        player2!.stop()
    }

}


SecondViewController でも新たにBGMを設定すれば、間違いと同時にBGMを止めることはできますが、前画面から垂れ流しているBGMを止める方法がわかりません。(以降、Third・Fourth画面等も同様)
どのようにすれば、前画面から垂れ流しているBGMを止めることができるでしょうか。ご教授をよろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • fuzzball

    2017/10/03 09:44

    ナビゲーションコントローラを使っていますか?

    キャンセル

  • mokoporon

    2017/10/04 15:30

    恥ずかしながら、初心者でイマイチ使い方が分からなかったため、使用していません。

    キャンセル

回答 1

checkベストアンサー

+1

曲を管理するシングルトンなクラスを作って下さい。
シングルトンが分からなければAppDelegateでもいいと思います。(とりあえずは)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/04 15:29

    ご回答ありがとうございます。お返事が遅れてしまい申し訳ありません。

    AppDelegateについてなのですが、質問をした直後、私なりに少々調べ
    http://trade-and-develop.hatenablog.com/entry/2015/12/06/221851

    こちらを参照すれば自己解決できるのではないかと思い、古いバージョンと注意されそうなところは自分なりに変更しつつ、実際にコードを写させていただきました。以下の二点を変更し、あとは上記参考サイト様のとおり書いています。

    [変更前]NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("bgm", ofType: "mp3")!)
    [変更後]Bundle.main.bundleURL.appendingPathComponent("bgm.mp3")

    [変更前]audioPlayer = try? AVAudioPlayer(contentsOfURL:sound_data)
    [変更後]audioPlayer = try? AVAudioPlayer(contentsOf:sound_data)

    すると、class AppDelegate: UIResponder, UIApplicationDelegate の行で
    「Invalid redeclaration of 'AppDelegate'」というエラーが出てきます。意味を調べると、「AppDelegateは無効な再宣言」ということで、なぜこのエラーが出るのか分からずに困っています。

    https://samekard.blogspot.jp/2014/09/swifterror.html
    上記のサイトによれば、「新しいクラスや構造体を定義しようとしたが、そのクラス名はすでにある場合」に出るらしいのですが、そのようなクラス名を使用した覚えはなく…。

    もう少し、初心者に付き合っていただけると助かります。

    キャンセル

  • 2017/10/04 15:33

    AppDelegateは新規に作成するのではなく、元々あるAppDelegate.swiftを使って下さい。

    キャンセル

  • 2017/10/04 16:30

    お早いご回答ありがとうございます!
    しっかりと見ておらず、恥ずかしいことを書いてしまっていたようですね…。

    AppDelegate.swiftにて上記参考サイト様のコードを書き、止めたいクラスに記すことでBGMを重複させることなく止めることができました。ありがとうございました!

    また機会があればよろしくお願いいたします!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.60%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Swift

    7041questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Xcode

    4000questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。