pausing spritekit game on app launch / exit .. iOS8

末鹿安然 提交于 2019-11-28 21:39:36

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)
}

Here is an Obj-C example completely based on answer given by 0x141E, without subclassing a view. In my case, because I have internal game states, like finished, paused and started, I had to make an additional check in overridden setPaused: method. But this worked flawlessly for me and definitely it is the one possible way to go.

AppDelegate.m

- (void)applicationDidBecomeActive:(UIApplication *)application {

    [[NSNotificationCenter defaultCenter] postNotificationName:@"stayPausedNotification" object:nil];
}

GameScene.m

@interface GameScene()

@property (nonatomic, assign) BOOL stayPaused;

@end

@implementation GameScene

//Use initWithCoder: if you load a scene from .sks file, because initWithSize is not called in that case.

-(instancetype)initWithSize:(CGSize)size{ 

    if(self = [super initWithSize:size]){

        _stayPaused = NO;


         //register to listen for event
        [[NSNotificationCenter defaultCenter]
         addObserver:self
         selector:@selector(setStayPaused)
         name:@"stayPausedNotification"
         object:nil ];
    }
    return self;
}

-(void)setStayPaused{

    self.stayPaused = YES;
}

-(void)setPaused:(BOOL)paused{

    if (!self.stayPaused) {
        [super setPaused:paused];
    }
    self.stayPaused = NO;
}

-(void)willMoveFromView:(SKView *)view{

    [[NSNotificationCenter defaultCenter] removeObserver:self  name:@"stayPausedNotification" object:nil];
}

@end

I recently encountered the same issue. The stayPaused solution works fine for me. Thanks guys:)

However, I think the mechanism you use to set stayPaused is NOT robust. Just by calling setStayPaused once on App becoming active is not enough, engineers in apple may change the code of Sprite Kit and call setPaused(false) MORE THAN ONCE on activating (In fact, I think they just did!). The second setPaused(false) will resume the game as you set stayPaused back to false on the first call.

My suggestion is to directly set the stayPaused property yourself in your pauseGame/resumeGame functions, and remove the "self.stayPaused = NO;" from setPaused function. In this way, the default behavior of SpriteKit can do whatever it likes, but the game will stay paused as long as we want.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!