How to keep SpriteKit scene paused when app become

2019-01-26 13:29发布

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.

5条回答
手持菜刀,她持情操
2楼-- · 2019-01-26 13:39

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
    }
  }
}
查看更多
叛逆
3楼-- · 2019-01-26 13:44

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
        }
    }
}
查看更多
相关推荐>>
4楼-- · 2019-01-26 13:53

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;


}
查看更多
何必那么认真
5楼-- · 2019-01-26 13:57

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;
}
查看更多
叛逆
6楼-- · 2019-01-26 14:00

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!

查看更多
登录 后发表回答