0
votes

Okay, so in my SpriteKit game, I have an SKAction that waits and then calls a method. I have this action repeating forever. The methods spawns sprites. When I press a button (another sprite) the game pauses, and stops the action by removing it. When either resume or restart (also sprites) is pressed the action starts again and the sprites spawn.

However, when returning from the background (after the app is left) and the pause menu method automatically gets called, when I press the resume or restart button, the action does not run for some reason. Here's my code:

In GameScene.m:

-(void)createSceneContents {
self.isPaused = NO;
self.world = [SKNode node];


[self createUI];
[self createPauseMenu];

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

[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(wentToForeground) name:UIApplicationWillEnterForegroundNotification object:nil];

[self addChild:self.world];
[self.world addChild:bottom];
[self.world addChild:self.player];
[self addChild:left];
[self addChild:right];
[self addChild:self.pause];
[self addChild:self.scoreLabelInGame];
[self addChild:self.actualScore];



}

-(void)createUI {

self.pause = [SKSpriteNode spriteNodeWithImageNamed:@"pausebutton.png"];
self.pause.size = CGSizeMake(self.customUnit,self.customUnit);
self.pause.name = @"pauseButton";
self.pause.position = CGPointMake(30, self.frame.size.height - 30);

self.scoreLabelInGame = [SKLabelNode labelNodeWithFontNamed:@"Futura"];
self.scoreLabelInGame.text = @"";
self.scoreLabelInGame.fontSize = 25;
self.scoreLabelInGame.position = CGPointMake(self.frame.size.width - 100, self.frame.size.height - 40);

self.actualScore = [SKLabelNode labelNodeWithFontNamed:@"Futura"];
self.actualScore.text = @"SCORE: 0";
self.actualScore.fontSize = 25;
self.actualScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeRight;
self.actualScore.position = CGPointMake(self.frame.size.width - 20, self.frame.size.height - 40);


self.deathImage = [SKSpriteNode spriteNodeWithImageNamed:@"youdied.png"];
self.deathImage.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)*1.5);


}

-(void)createPauseMenu {
self.pausedImage = [SKSpriteNode spriteNodeWithImageNamed:@"paused.png"];
self.pausedImage.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)*1.5);

self.restart = [SKLabelNode labelNodeWithFontNamed:@"Futura"];
self.restart.text = @"RESTART";
self.restart.fontSize = 25;
self.restart.position = CGPointMake(CGRectGetMidX(self.frame), self.pausedImage.position.y - self.pausedImage.position.y/5);

self.resume = [SKLabelNode labelNodeWithFontNamed:@"Futura"];
self.resume.text = @"RESUME";
self.resume.fontSize = 25;
self.resume.position = CGPointMake(self.restart.position.x, self.restart.position.y - self.customUnit);
}

-(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];

}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];


if([self.pause containsPoint:location] && self.isPaused == NO){

    [self pauseGame];

}else if([self.resume containsPoint:location] && self.isPaused == YES) {
    [self resumeGame];
}else if ([self.restart containsPoint:location] && self.isPaused == YES){

    [self restartGame];

}else if (self.isTouchingGround == YES && self.isPaused == NO) {
    [self.playerData jump:self.player];
    NSLog(@"GOD YES");
    self.isTouchingGround = NO;
}
}

-(void)pauseGame {
[self createPauseMenu];
NSLog(@"Pausing...");
[self removeActionForKey:@"spawn"];
self.world.paused = YES;
[self addChild:self.pausedImage];
[self addChild:self.restart];
[self addChild:self.resume];

NSString *path = [NSString stringWithFormat:@"%@/menu_music.mp3", [[NSBundle mainBundle]resourcePath]];
NSURL *pauseMusicURL = [NSURL fileURLWithPath:path];
self.pauseMusicPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:pauseMusicURL error:nil];
self.pauseMusicPlayer.numberOfLoops = -1;
[self.pauseMusicPlayer play];

[self.pause removeFromParent];
self.scoreLabelInGame.position = CGPointMake(self.restart.position.x, self.resume.position.y - self.customUnit);
self.actualScore.position = CGPointMake(self.restart.position.x, self.scoreLabelInGame.position.y - self.customUnit);
self.isPaused = YES;
[self.mainMusicPlayer pause];
}

-(void)restartGame {
[self removeAllChildren];
[self removeAllActions];
self.enemyData = nil;
self.isPaused = NO;
[self.pauseMusicPlayer stop];
[self createSceneContents];
[self runAction:self.spawnAction withKey:@"spawn"];
}

-(void)resumeGame {
self.isPaused = NO;
[self.pauseMusicPlayer stop];
[self runAction:self.spawnAction withKey:@"spawn"];
self.scoreLabelInGame.position = CGPointMake(self.frame.size.width - 100, self.frame.size.height - 40);
self.actualScore.position = CGPointMake(self.frame.size.width - 20, self.frame.size.height - 40);
[self.mainMusicPlayer play];
[self.restart removeFromParent];
[self.resume removeFromParent];
[self.pausedImage removeFromParent];
[self addChild:self.pause];

}

-(void)gameOver {
NSLog(@"Game Over");
GameDataHelper *gameData = [[GameDataHelper alloc]init];

[self removeActionForKey:@"spawn"];
[self addChild:self.restart];
[self addChild:self.deathImage];
SKAction *gameOverSound = [SKAction playSoundFileNamed:@"gameover_tune.mp3" waitForCompletion:NO];
[self runAction:gameOverSound];

NSString *path = [NSString stringWithFormat:@"%@/menu_music.mp3", [[NSBundle mainBundle]resourcePath]];
NSURL *pauseMusicURL = [NSURL fileURLWithPath:path];
self.pauseMusicPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:pauseMusicURL error:nil];
self.pauseMusicPlayer.numberOfLoops = -1;
[self.pauseMusicPlayer play];
[self.pause removeFromParent];

SKLabelNode *highScore = [SKLabelNode labelNodeWithFontNamed:@"Futura"];
NSString *highScoreText = [NSString stringWithFormat:@"HIGHSCORE: %ld",[GameDataHelper sharedGameData].highScore];
highScore.text = highScoreText;
highScore.fontSize = 25;
highScore.position = CGPointMake(self.frame.size.width/2, self.restart.position.y - (2*self.customUnit));
[self addChild:highScore];

self.scoreLabelInGame.position = CGPointMake(self.restart.position.x, self.resume.position.y - self.customUnit);
self.actualScore.position = CGPointMake(self.restart.position.x, self.scoreLabelInGame.position.y - self.customUnit);
self.isPaused = YES;
[self.mainMusicPlayer pause];
   [gameData save];
}

-(void)wentToForeground {
[self pauseGame];
}

In Enemy.m:

-(SKSpriteNode *)createEnemyWithSize:(float)size andWidth:(float)width andHeight:(float)height {
self.enemy = [SKSpriteNode spriteNodeWithImageNamed:@"block.png"];
self.enemy.size = CGSizeMake(size - 5, size - 5);
self.enemy.name = @"fallingEnemy";
self.enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(size - 3, size - 3)];
self.enemy.physicsBody.restitution = 0;
self.enemy.physicsBody.allowsRotation = NO;
int randomSection = arc4random_uniform(7);
switch (randomSection) {
    case 0:

        self.enemy.position = CGPointMake(2.5 + self.enemy.size.width/2, height-5);

        break;
    case 1:


        self.enemy.position = CGPointMake(width/7 + self.enemy.size.width/2, height-5);

        break;
    case 2:

        self.enemy.position = CGPointMake((width/7*2)  + self.enemy.size.width/2, height-5);

        break;
    case 3:

        self.enemy.position = CGPointMake((width/7*3)  + self.enemy.size.width/2, height-5);

        break;
    case 4:

        self.enemy.position = CGPointMake((width/7*4)  + self.enemy.size.width/2, height-5);

        break;
    case 5:

        self.enemy.position = CGPointMake((width/7*5)  + self.enemy.size.width/2, height-5);

        break;
    case 6:

        self.enemy.position = CGPointMake((width/7*6)  + self.enemy.size.width/2, height-5);


        break;
    default:

        break;
}


return self.enemy;
}
1
too much code, please narrow it down. I wonder ehy you stop the action when you want to pause. If you set a node's paused property, it will also pause its actions and resume them when paused is set back to NOLearnCocos2D
If I don't stop the action it just keeps on spawning and when I resume tons of sprites are spawnendSquid
Is the button-press called? So if you resume the game, does the app recognize the touch on the resume button?Christian
Yes that all works fineSquid
the actions keep running because you don't set the paused property of the node running the action, either do that or run the action on a node that actually gets pausedLearnCocos2D

1 Answers

0
votes

Even though you might have found the answer already i see some problems with your code:

Note: self.spawnAction needs to be a Strong property so maintain the reference when it's removed.

You are running the action on self.world, but removing it on self.

[self.world runAction:self.spawnAction withKey:@"spawn"];

[self removeActionForKey:@"spawn"];
self.world.paused = YES;

If you set the paused property of self.world to YES you do not need to remove the action as pause will immediately pause all actions.

You do not set the paused property to NO again on -(void)resumeGame

And you run it on self instead of self.world on resume.

Overall I would try to avoid using paused properties which might behave different and not give the results you want.

Also, keep in mind that removing nodes and actions don't happen instantly so if you pause nodes afterwards you might not get expected results.

Also, there is a limited amount of time you have on didEnterBackground to do your stuff before the it actually goes to background.

Hope it helps.