2

Okay, I have a scene in which I have this method, createSceneContents, that gets called when didMoveToView gets called. In this method I have a couple of things that create the scenes, including a timer that spawns nodes like this:

self.spawningSpeed = 1.5;
self.enemyData = [[Enemy alloc]init];
SKAction *wait = [SKAction waitForDuration:1.5];
SKAction *run = [SKAction performSelector:@selector(spawningEnemy) onTarget:self];
self.spawnAction = [SKAction repeatActionForever:[SKAction sequence:@[wait,run]]];
[self.world runAction:self.spawnAction withKey:@"spawn"];

enemyData is an object of my enemy class which basically just adds a SKSpriteNode to the scene. The world node is simply a node that I add all the game elements to.

This is what happens in the spawningEnemy method:

-(void)spawningEnemy {

NSLog(@"spawned");
SKSpriteNode *aNewEnemy = [self.enemyData createEnemyWithSize:self.customUnit andWidth:self.frame.size.width andHeight:self.frame.size.height + self.player.position.y];
aNewEnemy.physicsBody.allowsRotation = NO;
aNewEnemy.physicsBody.categoryBitMask = self.enemyCategory;
aNewEnemy.physicsBody.collisionBitMask = self.enemyCategory | self.playerCategory | self.edgeCategory | self.bottomCategory;
aNewEnemy.physicsBody.contactTestBitMask = self.enemyCategory | self.playerCategory | self.edgeCategory | self.bottomCategory;
[self.world addChild:aNewEnemy];

}

This just gets an SKSpriteNode from the enemy class and sets some properties. It also adds it to the world.

I also have 4 methods that pause, resume, restart and game-over the game:

-(void)pauseGame {
[self createPauseMenu];
NSLog(@"Pausing...");
self.world.paused = YES;
self.isPaused = YES;

}
-(void)restartGame {
[self removeAllChildren];
[self removeAllActions];
self.enemyData = nil;
self.isPaused = NO;
[self createSceneContents];
}

-(void)resumeGame {
self.isPaused = NO;
self.world.paused = NO;
}

-(void)gameOver {
NSLog(@"Game Over");
self.world.paused = YES;

self.isPaused = YES;

}

There's more in these methods, but this is all that really matters.

Now here's the problem: This all works fine until I exit the app. When returning to the app, the game automatically calls the pause method, but then I hit restart or resume, the spawningEnemy method is not being called. (I checked with an NSLog message as you can see)

What might have caused this?

Squid
  • 315
  • 1
  • 11
  • When returning to your app just re-run the SKActions you need. – sangony Jan 31 '15 at 17:20
  • I am doing it: when returning to the app the pause method gets called, and when you then resume or restart the action automatically gets called. – Squid Jan 31 '15 at 18:37
  • From the code you posted the only thing you are doing is setting self.isPaused = NO; and self.world.paused = NO; So where/when are you re-running your SKActions? – sangony Jan 31 '15 at 18:49
  • yes and when the world is paused the action stops, and when it resumes the action resumes because it is a child of the world node – Squid Jan 31 '15 at 18:50
  • Obviously it's not working so create a method which specifically re-runs any SKActions not working after the app comes back from the pause. Additionally you can remove all SKActions before your app goes into background to be sure you do not double up upon return. – sangony Jan 31 '15 at 18:55
  • Put the first code segment you have posted into a method. Then call that method from within your resumeGame method. – sangony Jan 31 '15 at 20:02
  • Tried it, doesn't work – Squid Jan 31 '15 at 20:03
  • I am really confused by this, why should entering the background affect any of this – Squid Jan 31 '15 at 20:03
  • I don't see anything obvious with the code you supplied, however I would try logging out self.world and its actions at the end of the restart method. Make sure self.world doesn't get turned to nil and make sure the action is sill on self.world. Also does gameover work properly? – Skyler Lauren Jan 31 '15 at 20:18
  • everything works, except for when i leave the app and then come back – Squid Jan 31 '15 at 20:34
  • Did you try logging out self.world and the actions it has at the very end of your restart method? – Skyler Lauren Feb 01 '15 at 04:22
  • Yes, i remove all children and actions as you can see in the code – Squid Feb 01 '15 at 10:36
  • Bah. Sorry I said restart meant at the end of resumeGame. Did you end up finding a solution? – Skyler Lauren Feb 01 '15 at 15:41

2 Answers2

1

I have tried the below code and it works. The spawning stops when the app resigns active and starts itself again once the app becomes active again.

You do not need to manually include code to pause as SpriteKit will pause itself when resigning active but I included it to show how to communicate between the AppDelegate and SKScene.

AppDelegate.m

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

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

GameScene.m

-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
    SKAction *wait = [SKAction waitForDuration:1.5];
    SKAction *run = [SKAction performSelector:@selector(spawningEnemy) onTarget:self];
    SKAction *spawnAction = [SKAction repeatActionForever:[SKAction sequence:@[wait,run]]];
    [self runAction:spawnAction withKey:@"spawn"];

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

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(resumeGame)
                                                 name:@"applicationDidBecomeActive"
                                               object:nil];
    }
return self;
}

-(void)spawningEnemy {
    NSLog(@"spawningEnemy");
}

-(void)pauseGame {
    NSLog(@"applicationWillResignActive...");
    self.paused = YES;
}

-(void)resumeGame {
    NSLog(@"applicationDidBecomeActive...");
    self.paused = NO;
}

-(void)willMoveFromView:(SKView *)view {
// good housekeeping
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
sangony
  • 11,636
  • 4
  • 39
  • 55
  • this works, kind of, but how do I call pauseGame whenever I re-open the app? – Squid Feb 01 '15 at 11:41
  • @Squid - you add [self pauseGame]; into the resumeGame method. – sangony Feb 01 '15 at 14:12
  • But then everytime I resume the game when I'm in the pause menu, it automatically reopens the pause menu. The resume method is called when the resume button is pressed in the pause menu – Squid Feb 01 '15 at 14:21
  • @Squid - you need tho think about the flow of your code. I've provided the code you asked for. How you implement it with your app is up to you. – sangony Feb 01 '15 at 14:42
  • It is still not working sadly, due to the same reason – Squid Feb 06 '15 at 19:35
0

If it is the whole scene that you want to have paused, then you should only pause the SKView containing the scene. This will pause all animations, run loops and interaction of the scene and all nodes within the scene.

Also experience learned me that it is good practice to pause the scene when the application goes to the background and resume when it returnes to the foreground. It prevents issues such as: Sprite Kit & playing sound leads to app termination

Community
  • 1
  • 1
Thomm
  • 506
  • 5
  • 12