I tried to search everywhere in the code:Explained documentry what it does when going to background, or if it is even paused sometime, but to no avail- can someone direct me
iPad seems to background ok, but iPhone definitely crashes when backgrounding a sprite kit game. You have to do this manually, the automagical piece isn't so automagical.
For me did not work none of one provided solutions. I did found another way how to do it.
// In the AppDelegate
- (void)applicationWillResignActive:(UIApplication *)application
{
if ([self.window.rootViewController isKindOfClass:[GameViewController class]]) {
GameViewController *vc = (GameViewController*)self.window.rootViewController;
[vc pauseGame];
[vc.view addObserver:vc
forKeyPath:@"paused"
options:NSKeyValueObservingOptionNew
context:nil];
}
}
// In the GameViewController
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
SKView *skView = (SKView*)self.view;
MainGame *mainGame = (MainGame*)skView.scene;
if ([keyPath isEqualToString:@"paused"] &&
[[change objectForKey:NSKeyValueChangeNewKey] boolValue] == NO &&
[mainGame isGameInProgress]) {
[self.view removeObserver:self forKeyPath:@"paused" context:nil];
skView.paused = YES;
}
}
I was wondering why in the world this seemingly simple solution was causing me crashes on app startup, but it was because I had iAd running.
So, a thing to keep in mind: @MassivePenguin's answer works but if you have iAd going you will have to grab the SKView
via the subviews
or it (obviously) crashes.
-(SKView*)getSKViewSubview{
for (UIView* s in self.window.rootViewController.view.subviews) {
if ([s isKindOfClass:[SKView class]]) {
return (SKView*)s;
}
}
return nil;
}
- (void)applicationWillResignActive:(UIApplication *)application {
SKView* view = [self getSKViewSubview];
if (view) {
view.paused = YES;
}
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
SKView* view = [self getSKViewSubview];
if (view) {
view.paused = NO;
}
}
Sprite Kit automatically pauses its animation timers when moving to the background -- you don't need to worry about your app getting killed for that.
As said here by LearnCocos2D
:
The problem is AVAudioSession can't be active while the app enters background.
The fix is quite simple, and also applies to ObjectAL => set the AVAudioSession to inactive while the app is in background, and reactivate the audio session when the app enters foreground.
A simplified AppDelegate with this fix looks like so:
#import <AVFoundation/AVFoundation.h>
...
- (void)applicationWillResignActive:(UIApplication *)application
{
// prevent audio crash
[[AVAudioSession sharedInstance] setActive:NO error:nil];
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// prevent audio crash
[[AVAudioSession sharedInstance] setActive:NO error:nil];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// resume audio
[[AVAudioSession sharedInstance] setActive:YES error:nil];
}
PS: this fix will be included in Kobold Kit v7.0.3.
SpriteKit really isn't documented that well yet, probably because it's so new that relatively few developers have implemented it. SpriteKit should pause animations when backgrounding, but in my experience (and harrym17's) it will cause memory access errors and quits the app entirely rather than backgrounding it.
According to the Apple Developer forums, it seems this is a known bug in SpriteKit (it doesn't always pause animations when backgrounding, as it should) causing memory access errors as per harrym17's comment. Here's a brief fix which has worked for me - my app was consistently crashing when backgrounding, and since adding this code everything works fine.
(Kudos to Keith Murray for this code on the Apple forums; as far as I can see he hasn't posted it on SO).
In AppDelegate.h
, make sure you import SpriteKit:
#import <SpriteKit/SpriteKit.h>
In AppDelegate.m
, edit your applicationWillResignActive
method:
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// 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.
// pause sprite kit
SKView *view = (SKView *)self.window.rootViewController.view;
view.paused = YES;
}
And this to your applicationDidBecomeActive
method:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// 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.
// resume sprite kit
SKView *view = (SKView *)self.window.rootViewController.view;
view.paused = NO;
}
There are additional problems when backgrounding when playing audio via AVAudioSession
, apparently; a workaround is mentioned in this thread.