I am working on a game that is nearing completion, but I ran into one problem that I'm not able to solve myself (To be honest, there's multiple, but let's save that for other questions).
My game is organized like this: MainMenu --> GameScene --> Pause/GameOver The Pause and GameOver menus are basically just overlays made out of Sprite and Label nodes.
In the game, there is a player that needs to avoid touching enemies, that spawn every x amount of time. I achieve this by repeating an SKAction that runs a code block forever.
When the game pauses (When the pause-button is hit), it changes a boolean (isPaused) to YES, which causes every method to stop. It also removes the enemy-spawning action.
When the game restarts, it deletes everything that is currently there and recreates the entire scene.
Here's the problem: Whenever I click on the pause-button, so the menu shows up and then exit the app (just background not actually quitting) and come back and press restart, the enemies do not spawn ergo the action does not run (the node-count does not go up either I checked).
Here's some code:
I will not put in everything so if you find something referring to something that isn't there, that thing probably is there in the original code.
In GameScene.m:
-(void)didMoveToView:(SKView *)view {
if (!self.contentCreated) {
[self createSceneContents];
self.contentCreated = YES;
}
}
-(void)createSceneContents {
self.isTouchingGround = NO;
self.isPaused = NO;
self.world = [SKNode node];
NSLog(@"likewhatever");
self.playerCategory = 1;
self.enemyCategory = 2;
self.edgeCategory = 4;
self.bottomCategory = 8;
self.playerScore = 0;
[GameDataHelper sharedGameData].score = 0;
self.physicsWorld.contactDelegate = self;
SKSpriteNode *bottom = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:CGSizeMake(self.frame.size.width, 10)];
bottom.position = CGPointMake(self.frame.size.width/2, 0);
bottom.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:bottom.size];
bottom.physicsBody.dynamic = NO;
bottom.physicsBody.restitution = 0;
bottom.physicsBody.categoryBitMask = self.bottomCategory;
bottom.physicsBody.contactTestBitMask = self.playerCategory | self.enemyCategory;
SKSpriteNode *left = [[SKSpriteNode alloc]init];
left.size = CGSizeMake(1, self.frame.size.height);
left.position = CGPointMake(0, self.frame.size.height/2);
left.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:left.size];
left.physicsBody.dynamic = NO;
left.physicsBody.restitution = 0;
SKSpriteNode *right = [[SKSpriteNode alloc]init];
right.size = CGSizeMake(1, self.frame.size.height);
right.position = CGPointMake(self.frame.size.width - 1, self.frame.size.height/2);
right.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:right.size];
right.physicsBody.dynamic = NO;
right.physicsBody.restitution = 0;
self.backgroundColor = [SKColor blackColor];
self.playerData = [[Player alloc]init];
self.customUnit = self.frame.size.width/7;
self.player = [self.playerData newPlayer:self.customUnit];
self.player.physicsBody.categoryBitMask = self.playerCategory;
self.player.physicsBody.contactTestBitMask = self.enemyCategory | self.edgeCategory | self.bottomCategory;
self.player.position = CGPointMake(CGRectGetMidX(self.frame), self.customUnit*5);
[self.playerData movementSetup];
[self createUI];
NSString *path = [NSString stringWithFormat:@"%@/gamemusic2.mp3", [[NSBundle mainBundle]resourcePath]];
NSURL *mainMusicURL = [NSURL fileURLWithPath:path];
self.mainMusicPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:mainMusicURL error:nil];
self.mainMusicPlayer.volume = 0.1;
self.mainMusicPlayer.numberOfLoops = -1;
[self.mainMusicPlayer play];
[self spawnObject];
[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.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);
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)spawnObject {
NSLog(@"called");
if (self.isPaused == NO){
NSLog(@"notpaused");
self.spawningSpeed = 1.5;
self.enemyData = [[Enemy alloc]init];
SKAction *wait = [SKAction waitForDuration:self.spawningSpeed];
SKAction *run = [SKAction runBlock:^{
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];
}];
SKAction *action = [SKAction repeatActionForever:[SKAction sequence:@[wait,run]]];
[self runAction:action withKey:@"spawn"];
}
}
-(void)didBeginContact:(SKPhysicsContact *)contact {
if (self.isPaused == NO) {
SKPhysicsBody *firstBody, *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
firstBody = contact.bodyA;
secondBody = contact.bodyB;
}else {
firstBody = contact.bodyB;
secondBody = contact.bodyA;
}
if (firstBody.categoryBitMask == self.playerCategory && secondBody.categoryBitMask == self.bottomCategory) {
self.isTouchingGround = YES;
}
if (firstBody.categoryBitMask == self.playerCategory && secondBody.categoryBitMask == self.enemyCategory) {
self.isTouchingGround = YES;
if ([secondBody.node.name isEqualToString:@"fallingEnemy"] && self.player.position.y < secondBody.node.position.y) {
[self gameOver];
}
}
if (firstBody.categoryBitMask == self.enemyCategory && secondBody.categoryBitMask == self.enemyCategory) {
[self.enemyData changeBlock:firstBody.node];
[self.enemyData changeBlock:secondBody.node];
[self impactSound];
[self updateScore];
NSLog(@"Change1");
}
if (firstBody.categoryBitMask == self.enemyCategory && secondBody.categoryBitMask == self.bottomCategory) {
NSLog(@"Change2");
[self.enemyData changeBlock:firstBody.node];
[self impactSound];
[self updateScore];
}
}
}
-(void)pauseGame {
NSLog(@"Pausing...");
[self removeActionForKey:@"spawn"];
[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.isPaused = NO;
[self.pauseMusicPlayer stop];
[self createSceneContents];
}
-(void)resumeGame {
self.isPaused = NO;
[self.pauseMusicPlayer stop];
[self spawnObject];
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];
}
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;
}
-(void)changeBlock:(SKNode *)block{
block.physicsBody.dynamic = NO;
block.name = @"staticEnemy";
}