Search code examples
iosswiftios8sprite-kitnsnotificationcenter

pausing spritekit game on app launch / exit .. iOS8


I've read everything I could find on this topic and still cant figure out my issue. I have tried pausing my game in every area of appdelegate

func applicationWillResignActive(application: UIApplication!) {
    NSNotificationCenter.defaultCenter().postNotificationName("pauseGameScene", object: self)
}

func applicationDidEnterBackground(application: UIApplication!) {
    NSNotificationCenter.defaultCenter().postNotificationName("pauseGameScene", object: self)
}

func applicationWillEnterForeground(application: UIApplication!) {
    NSNotificationCenter.defaultCenter().postNotificationName("pauseGameScene", object: self)
}

func applicationDidBecomeActive(application: UIApplication!) {
    NSNotificationCenter.defaultCenter().postNotificationName("pauseGameScene", object: self)
}

In my controller:

override func viewDidLoad() {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "pauseGame:", name: "pauseGameScene", object: nil)
}

func pauseGame(){
    self.skView.paused = true
    self.skView.scene!.paused = true
}

i know pauseGame works because if i toggle it with a button in my scene, it will stop the game. Even if I pause my skview and scene directly after they are loaded in the controller.. the game will not be paused on launch. It's easy to pause the game when I'm in-game. but for some reason whenever i exit and resume the app, the game will un-pause itself.

i notice if i get hacky and use some kind of delay.. i can get it to work. but obviously this is very stupid.. i just need to know where the game is unpausing itself!

func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

func pauseGame(sender: UIButton!){

    delay(2) {
        println("blah")
        self.skView.paused = true
        self.skView.scene!.paused = true
    }
}

Solution

  • Here's a way to keep the view paused after returning from background mode.

    Xcode 7 (see below for Xcode 8 instructions)

    In the storyboard,

    1) Change the class of the view to MyView

    In the View Controller,

    2) Define an SKView subclass with a boolean named stayPaused

    class MyView: SKView {
        var stayPaused = false
    
        override var paused: Bool {
            get {
                return super.paused
            }
            set {
                if (!stayPaused) {
                    super.paused = newValue
                }
                stayPaused = false
            }
        }
    
        func setStayPaused() {
            if (super.paused) {
                self.stayPaused = true
            }
        }
    }
    

    3) Define the view as MyView

    4) Add a notifier to set the stayPaused flag

    class GameViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
                // Configure the view.
                let skView = self.view as MyView
    
                NSNotificationCenter.defaultCenter().addObserver(skView, selector:Selector("setStayPaused"), name: "stayPausedNotification", object: nil)
    

    In the App Delegate,

    5) Post a notification to set the stay paused flag when the app becomes active

    func applicationDidBecomeActive(application: UIApplication) {
        NSNotificationCenter.defaultCenter().postNotificationName("stayPausedNotification", object:nil)
    }
    

    Xcode 8

    In the storyboard,

    1) Change the class of the view from SKView to MyView

    In the View Controller,

    2) Define an SKView subclass with a boolean named stayPaused

    class MyView: SKView {
        var stayPaused = false
    
        override var isPaused: Bool {
            get {
                return super.isPaused
            }
            set {
                if (!stayPaused) {
                    super.isPaused = newValue
                }
                stayPaused = false
            }
        }
    
        func setStayPaused() {
            if (super.isPaused) {
                self.stayPaused = true
            }
        }
    }
    

    3) Define the view as MyView

    4) Add a notifier to set the stayPaused flag

    class GameViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            if let view = self.view as! MyView? {
                NotificationCenter.default.addObserver(view, selector:#selector(MyView.setStayPaused), name: NSNotification.Name(rawValue: "stayPausedNotification"), object: nil)
    

    In the App Delegate,

    5) Post a notification to set the stay paused flag when the app becomes active

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "stayPausedNotification"), object: nil)
    }