Pinxaton
Pinxaton

Reputation: 457

How to keep SpriteKit scene paused when app becomes active?

Is there anyway to prevent SpriteKit from automatically unpausing a scene when entering foreground/becoming active?

I set paused = true and want it to remain so even when the app becomes active again after having been sent to the background.

I should add that I'm doing this in swift, though I would not have expected the behaviour to be different in this regard.

Upvotes: 9

Views: 3441

Answers (5)

user7721335
user7721335

Reputation:

I made some adaptions to the solution from Knight0fDragon to make it work for me. This makes it so that isPaused will always be equal to realPaused. In order to pause the game, the "realPaused" variable should then only be altered, which changes automatically also the isPaused variable.

var realPaused: Bool = false {
    didSet {
        self.isPaused = realPaused
    }
}
override var isPaused: Bool {
    didSet {
        if (self.isPaused != self.realPaused) {
            self.isPaused = self.realPaused
        }
    }
}

Unfortunately, this will prevent the scene from pausing when the application is running in the background. In order to prevent that, I changed the condition to: "self.isPaused != self.realPaused && self.isPaused == false" so that the scene will still pause automatically when the app is put to the background but will only re-actiate if realPaused is also true:

var realPaused: Bool = false {
    didSet {
        self.isPaused = realPaused
    }
}
override var isPaused: Bool {
    didSet {
        if (self.isPaused == false && self.realPaused == true) {
            self.isPaused = true
        }
    }
}

Upvotes: 6

Knight0fDragon
Knight0fDragon

Reputation: 16837

Not sure if it is the same in objective C, but in swift I had to "override" a callback function that SKView calls behind the scenes,

func CBApplicationDidBecomeActive()
{

}

This function was causing paused to be reset.

(note override keyword should not be applied)

In some cases where you want to just retain the state of pause, make a new variable instead and override the isPaused method.

class GameScene:SKScene
{
  var realPaused = false
  {
     didSet
     {
         isPaused = realPaused
     }
  }
  override var isPaused : Bool
  {
    get
    {
       return realPaused
    }
    set
    {
      //we do not want to use newValue because it is being set without our knowledge
      paused = realPaused
    }
  }
}

Upvotes: 5

Kum Chun Wai
Kum Chun Wai

Reputation: 31

this question may have been quite old, but I encountered the same problem today and I think I have found a pretty good solution to it:

In the AppDelegate, I do the following:

- (void)applicationDidBecomeActive:(UIApplication *)application 
{
    SKView *view = (SKView *)self.window.rootViewController.view;

    if ([view.scene isKindOfClass:[GameScene class]]) 
    {
        XGGameScene *scene = (GameScene *)view.scene;
        [scene resumeGame];
    }
}

And then in the GameScene class itself, I update a BOOL to reflect that the app has just resumed from background:

- (void)resumeGame
{
    //  Do whatever is necessary

    self.justResumedFromBackground = YES;
}

And finally, in the update: loop, I run the following:

- (void)update:(NSTimeInterval)currentTime
{
    // Other codes go here...

    // Check if just resumed from background.
    if (self.justResumedFromBackground) 
    {
        self.world.paused = YES;
        self.justResumedFromBackground = NO;
    }

    // Other codes go here...
}

Hope this helps!

Upvotes: 3

dragoneye
dragoneye

Reputation: 701

Pinxaton you are right but you can paused application by adding a small delay

 (void)theAppIsActive:(NSNotification *)note 
{
    self.view.paused = YES;
       SKAction *pauseTimer= [SKAction sequence:@[
                                                [SKAction waitForDuration:0.1],
                                                [SKAction performSelector:@selector(pauseTimerfun)
                                                                 onTarget:self]

                                                ]];
    [self runAction:pauseTimer withKey:@"pauseTimer"];
}

-(void) pauseTimerfun
{
     self.view.paused = YES;


}

Upvotes: 2

Scooter
Scooter

Reputation: 4166

You should make use of your app delegate, specifically the applicationDidBecomeActive method. In that method send a notification that your SpriteKit view listens for.

So in the applicationDidBecomeActive method your code should look something like this:

// Post a notification when the app becomes active
[[NSNotificationCenter defaultCenter] postNotificationName:@"appIsActive" object:nil];    

Now in your didMoveToView method in your SKScene file put the following:

// Add a listener that will respond to the notification sent from the above method
 [[NSNotificationCenter defaultCenter] addObserver:self 
                                          selector:@selector(theAppIsActive:) 
                                              name:@"appIsActive" object:nil];

Then just add this method to your SKScene file:

//The method called when the notification arrives
(void)theAppIsActive:(NSNotification *)note 
{
    self.view.paused = YES;
}

Upvotes: 1

Related Questions