Pausing Spritekit Game Using Appdelegate in iOS8

pausing spritekit game on app launch / exit .. iOS8

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

Pausing a SpriteKit Game - UIApplicationWillResignActive vs. UIApplicationDidBecomeActive?

Pausing

This is from the docs about applicationWillResignActive method:

You should use this method to pause ongoing tasks, disable timers, and
throttle down OpenGL ES frame rates. Games should use this method to
pause the game. An app in the inactive state should do minimal work
while it waits to transition to either the active or background state.

So this method is meant to be used when it comes to pausing the games.

Unpausing

iirc, game should be automatically unpaused when app transition from inactive to active state. This is the moment when applicationDidBecomeActive method is called, so in some cases you may want to pause the game here as well... But that depends on your game.

I don't know why did you mention combination of applicationDidBecomeActive & applicationDidEnterBackground for pausing/unpausing... Because it is probably too late to pause the game in applicationDidEnterBackground and technically it is not needed to unpause the game in applicationDidBecomeActive because this is done automatically.

Spritekit game crashes when pausing scene from app delegate

Add a new method in appDelegate:

- (SKView *)getGameView {
NSArray *viewControllers = self.window.rootViewController.childViewControllers;
for (UIViewController *vc in viewControllers) {
if ([vc.view isKindOfClass:[SKView class]]) {
SKView *view = (SKView *)vc.view;
return view;
}
}
return nil;
}

and now ... modify your code from:

SKView *view = (SKView *)self.window.rootViewController.view;
view.paused = YES;

to:

SKView *view = [self getGameView];
if (view) {
view.paused = YES; //or NO
}

SpriteKit Autoresumes and auto pauses iOS8

I'm pretty sure it's a bug in spritekit. No matter what you do, the game will unpause itself in applicationDidBecomeActive

I asked the same question here. pausing spritekit game on app launch / exit .. iOS8 You have to subclass SKScene and override the paused property to get it to work. It's weird you have to do that. It really shouldnt have so many problems, but thats the only way I could get my game to stay paused

EDIT: okay, I translated the code to objective-c. I hope this is useful to you because my objective-c was rustier than i expected.

AppDelegate.m

- (void)applicationWillResignActive:(UIApplication *)application {
[[NSNotificationCenter defaultCenter]postNotificationName:@"pauseGameScene" object:nil];
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
[[NSNotificationCenter defaultCenter]postNotificationName:@"stayPausedNotification" object:nil];
}

SKView Subclass

@interface MySKView : SKView
- (void) setStayPaused;
@end

@implementation MySKView

bool _stayPaused = false;

- (void) setPaused:(BOOL)paused{
if (!_stayPaused) {
super.paused = paused;
}
_stayPaused = NO;

}

- (void) setStayPaused{
_stayPaused = YES;
}

@end

GameViewController

@interface GameViewController : UIViewController

-(void)pauseGame;

@end

@implementation GameViewController

SKScene *_scene;
MySKView *_skView;

-(void)pauseGame{
_skView.paused = YES;
_skView.scene.view.paused = YES;
}

- (void)viewDidLoad
{

[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(pauseGame) name:@"pauseGameScene" object:nil];

// Configure the view.

_skView = [[MySKView alloc]initWithFrame:self.view.frame];

_skView.showsFPS = YES;
_skView.showsNodeCount = YES;
/* Sprite Kit applies additional optimizations to improve rendering performance */
_skView.ignoresSiblingOrder = YES;

// Create and configure the scene.
_scene = [[GameScene alloc]initWithSize:_skView.frame.size];
_scene.scaleMode = SKSceneScaleModeAspectFill;

// Present the scene.
[self.view addSubview:_skView];
[_skView presentScene:_scene];

}

- (void)viewDidAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter]addObserver:_skView selector:@selector(setStayPaused) name:@"stayPausedNotification" object:nil];
}

@end

SKAction resumes when appDidBecomeActive() even when game is paused before appDidResignActive()

Change pauseGame() and resumeGame() methods to look like this:

private func pauseGame() {

node.speed = 0.0
gameState = .paused
pauseLayer.run(SKAction.fadeAlpha(to: 0.5, duration: 1))

}
private func resumeGame() {
pauseLayer.run(.fadeOut(withDuration: 1))
node.speed = 1.0
gameState = .inProgress
}

Note that I am using speed property instead of isPaused property... That is all the difference you need to make. Can't really say why this happens because this behaviour is not documented, but I have seen it already, and been writing about it probably more in detail in some of my previous posts.

Keep SpriteKit scene paused after app becomes active

This code makes no sense

GameViewController().pause(true)

because you are creating a new instance of GameViewController rather than accessing the current one.

Rather than pausing the whole scene you should just pause the nodes that you would liked paused. Usually you create some kind of worldNode in your game scene (Apple also does this in DemoBots)

class GameScene: SKScene {

let worldNode = SKNode()

// state machine, simple bool example in this case
var isPaused = false

....
}

than add it to the scene in DidMoveToView

override func didMoveToView(view: SKView) {
addChild(worldNode)
}

Than all nodes that you need paused you add to the worldNode

worldNode.addChild(YOURNODE1)
worldNode.addChild(YOURNODE2)

Than your pause function should look like this

 func pause() {
worldNode.paused = true
physicsWorld.speed = 0
isPaused = true
}

and resume like this

  func resume() {
worldNode.paused = false
physicsWorld.speed = 1
isPaused = false
}

Lastly to make sure the game is always paused when in paused add this to your update method. This ensures that you game does not resume by accident e.g due to app delegate, iOS alerts etc.

  override func update(currentTime: CFTimeInterval) {

if isPaused {
worldNode.paused = true
physicsWord.speed = 0
return
}

// Your update code
...
}

To call these from your AppDelegate you should use delegation or NSNotificationCenter as has been mentioned in one of the comments.

In gameScene create the NSNotifcationObserver in didMoveToView

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(pause), name: "Pause", object: nil) // in your app put the name string into a global constant property to avoid typos when posting 

and in appDelegate post it at the correct spot

NSNotificationCenter.defaultCenter().postNotificationName("Pause", object: nil)

The main benefit with the worldNode approach is that you can easily add pause menu sprites etc while the actual game is paused. You also have more control over your game, e.g having the background still be animated while game is paused.

Hope this helps.

Pausing iOS app game when User clicks Home Button

iOS can't magically pause or un-pause your game for you - it's something you have to handle on your own in the code.

Once you have the logic to un-pause the game you can get the 2 seconds delay you mentioned in your question by calling performSelector:withObject:afterDelay: (see the docs). For example:

[self performSelector:@selector(continueGame) withObject:nil afterDelay:2.0]

where self has a method called continueGame to .. continue the game. :)

How to pause a timer in SpriteKit by using AppDelegate, Swift?

This is what I did in my game. Just define the timer variable outside the GameScene Class instead of inside it.

var timer = NSTimer() //Define my timer outside my gamescene class so I could access it in App Delegate

class GameScene: SKScene {

}


Related Topics



Leave a reply



Submit