swifter
swifter

Reputation: 25

Swift: How to make a UISwitch button as a setting, according to game state?

How to make a "activate / deactivate background music" button in my settings?

Music is only played when the game's launched. (Tap "Start" to play -> Background music is played too.)

I have coded this for the moment but I really do not know how to do it.

class SettingsViewController: UITableViewController {
    // MARK: - IBOutlets
    @IBOutlet weak var backgroundgMusicLabel: UILabel!
    @IBOutlet weak var backgroundMusicSwitch: UISwitch!

    // MARK: - Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func backgroundMusicPressed(_ sender: Any) {
        if backgroundMusicSwitch.isOn {
            UserDefaults().set("On", forKey: "switch")
        } else {
            UserDefaults().set("Off", forKey: "switch")
        }
    }
}

My SettingsViewController

While I've this code in my MainViewController:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if game == .ready {
        start()
    }
}

And I play music like this:

var audioPlayer: AVAudioPlayer?

func playMusic() {
    let url = Bundle.main.url(forResource: "MyMusic", withExtension: "mp3")!
    do {
        audioPlayer = try AVAudioPlayer(contentsOf: url)
        guard let audioPlayer = audioPlayer else { return }
        audioPlayer.prepareToPlay()
        audioPlayer.play()
    } catch let error {
        print(error.localizedDescription)
    }
}

Upvotes: 2

Views: 359

Answers (2)

smohn
smohn

Reputation: 411

TheValyreanGroup is right with Globals.

class Globals: NSObject {
    static let sharedInstance = Globals()
    var audioPlayer: AVAudioPlayer?

    func playMusic() {
        let url = Bundle.main.url(forResource: "MyMusic", withExtension: "mp3")!
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: url)
            guard let audioPlayer = audioPlayer else { return }
            audioPlayer.prepareToPlay()
            audioPlayer.play()
        } catch let error {
            print(error.localizedDescription)
        }
    }
}

But in your case try the following code:

MainViewController:

static let sharedInstance = Globals()
let globalVars = Globals.sharedInstance

And add this func in your start() function:

func checkMusicStatus() {
    let status = UserDefaults().string(forKey: "switch")
    if status == "Off"{
        if (self.globalVars.audioPlayer?.isPlaying != nil){
            self.globalVars.audioPlayer?.stop()
        }
    } else {
        self.globalVars.playMusic()
    }
}

It should work, hope this will help.

Upvotes: 2

TheValyreanGroup
TheValyreanGroup

Reputation: 3599

When i need to do something like this i like to use a SharedInstance class. Some poeple call it a singleton, but i don't believe it actually is.

Create a new swift file and name it something like 'Globals'. Declare any variables or objects you'll want to share between VC's here and you can also create global functions as well. Keep in mind, these are all going to be the same instance. It's not the same as passing a variable between VC's or grabbing another instance of another VC.

Globals.swift

class Globals: NSObject {

    static let sharedInstance = Globals()

    var audioPlayer: AVAudioPlayer?

    func playMusic() {
        let url = Bundle.main.url(forResource: "MyMusic", withExtension: "mp3")!
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: url)
            guard let audioPlayer = audioPlayer else { return }
            audioPlayer.prepareToPlay()
            audioPlayer.play()
        } catch let error {
            print(error.localizedDescription)
        }
    }
}

Now, in any of your VC's, you declare a class scope variable of this new Globals class and use any of the objects from it by prepending globalVars

class SettingsViewController: UITableViewController {
    // MARK: - IBOutlets
    @IBOutlet weak var backgroundgMusicLabel: UILabel!
    @IBOutlet weak var backgroundMusicSwitch: UISwitch!

    let globalVars = Globals.sharedInstance()

    // MARK: - Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func backgroundMusicPressed(_ sender: Any) {
        if backgroundMusicSwitch.isOn {
            UserDefaults().set("On", forKey: "switch")
            self.globalVars.audioPlayer.play()  //Uses the same instance of the audioPlayer you created in the 'Globals' class
        } else {
            UserDefaults().set("Off", forKey: "switch")
            self.globalVars.audioPlayer.stop()
        }
    }
}

Since your playMusic function has moved to this new class, you'll call it the same way.

 self.globalVars.playMusic() 

I know a lot of people frown upon using so called 'global variables', however, i find this shared instance class extremely useful in many scenarios. Especially games. This is also how i keep a "running" class of all my extensions, subclasses, custom functions that can be repurposed, etc. I just include this same file in all of my projects and can access all of my favorite functions immediately.

Upvotes: 1

Related Questions