I checked the answer here and on other sites but didn't get a definitive solution.
I have two scenes
Scene 1:
class GameMenuScene: SKScene {
override func didMoveToView(view: SKView) {
// Add background
var background: SKSpriteNode = SKSpriteNode(imageNamed: "Starfield")
background.position = CGPointMake(-20, 0)
background.size = CGSizeMake(self.size.width + 40, self.size.height)
background.anchorPoint = CGPointZero
background.blendMode = SKBlendMode.Replace
self.addChild(background)
// Add game title
gameTitle = SKSpriteNode(imageNamed: "Title")
gameTitle.name = "Game Title"
gameTitle.xScale = scale
gameTitle.yScale = scale
gameTitle.position = CGPoint(x: CGRectGetMidX(self.frame), y: self.frame.height * 0.75)
self.addChild(gameTitle)
// Add scoreboard
scoreboard = SKSpriteNode(imageNamed: "ScoreBoard")
scoreboard.name = "Scoreboard"
scoreboard.xScale = scale
scoreboard.yScale = scale
scoreboard.position = CGPoint(x: CGRectGetMidX(self.frame), y: self.frame.height * 0.50)
self.addChild(scoreboard)
// Add play button
playButton = SKSpriteNode(imageNamed: "PlayButton")
playButton.name = "PlayButton"
playButton.xScale = scale
playButton.yScale = scale
playButton.position = CGPoint(x: CGRectGetMidX(self.frame), y: self.frame.height * 0.25)
self.addChild(playButton)
// Add menu score label
var menuScoreLabel = SKLabelNode()
menuScoreLabel.fontName = fontName
menuScoreLabel.fontSize = scoreFontsize
menuScoreLabel.text = String(score)
menuScoreLabel.position = CGPointMake(scoreboard.position.x - (scoreboard.size.width / 4), scoreboard.position.y - (scoreboard.size.height / 4))
menuScoreLabel.zPosition = 10
self.addChild(menuScoreLabel)
// Add menu top score label
var menuTopScoreLabel = SKLabelNode()
menuTopScoreLabel.fontName = fontName
menuTopScoreLabel.fontSize = scoreFontsize
menuTopScoreLabel.text = String(userDefaults.integerForKey("TopScore"))
menuTopScoreLabel.position = CGPointMake(scoreboard.position.x + (scoreboard.size.width / 4), scoreboard.position.y - (scoreboard.size.height / 4))
menuTopScoreLabel.zPosition = 10
self.addChild(menuTopScoreLabel)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
// Get touch location
var touchLocation = touch.locationInNode(self)
// Check if Play button is presssed
if playButton.containsPoint(touchLocation) == true {
//println("right node touched")
// Transition to GameScene.swift
var transition: SKTransition = SKTransition.fadeWithDuration(1)
// Configure the view.
let scene = GameScene()
let skView = self.view! as SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.size = skView.bounds.size
scene.scaleMode = .AspectFill
skView.presentScene(scene, transition: transition)
}
}
}
}
Scene 2:
class GameScene: SKScene, SKPhysicsContactDelegate {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
// Add background
var background: SKSpriteNode = SKSpriteNode(imageNamed: "Starfield")
background.position = CGPointMake(-20, 0)
background.size = CGSizeMake(self.size.width + 40, self.size.height)
background.anchorPoint = CGPointZero
background.blendMode = SKBlendMode.Replace
self.addChild(background)
// Add mainlayer & labelHolderLayer
self.addChild(mainLayer)
self.addChild(labelHolderLayer)
// Add cannon
cannon = SKSpriteNode(imageNamed: "Cannon")
cannon.name = "Cannon"
cannon.position = CGPoint(x: CGRectGetMidX(self.frame), y: 0)
self.addChild(cannon)
// Add score label
scoreLabel.name = "Score Label"
scoreLabel.fontName = fontName
scoreLabel.fontSize = scoreFontsize
scoreLabel.text = String(score)
scoreLabel.position = CGPointMake(CGRectGetMidX(self.frame), self.frame.size.height - scoreFontsize)
scoreLabel.zPosition = 10
self.addChild(scoreLabel)
// Add LivesDisplay
livesDisplay = SKSpriteNode(imageNamed: "Ammo5")
livesDisplay.name = "livesDisplay"
livesDisplay.position = CGPoint(x: self.size.width - livesDisplay.size.width, y: self.size.height - livesDisplay.size.height)
self.addChild(livesDisplay)
// Settings for new game
newGame()
}
func gameIsOver() {
// Set game over flag and stop movement
gameOver = 1
mainLayer.speed = 0
mainLayer.paused = true
// Add game over label
gameOverLabel.fontName = fontName
gameOverLabel.fontSize = gameOverFontsize
gameOverLabel.text = "Game Over!"
gameOverLabel.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
gameOverLabel.zPosition = 10
labelHolderLayer.addChild(gameOverLabel)
// Set main menu top score
if score > userDefaults.integerForKey("TopScore") {
userDefaults.setInteger(score, forKey: "TopScore")
userDefaults.synchronize()
}
// Run acton sequence (wait a few seconds before transitioning)
runAction(SKAction.sequence([SKAction.waitForDuration(1), SKAction.runBlock({ () -> Void in
// Transition back to GameMenuScene
var transition: SKTransition = SKTransition.fadeWithDuration(1)
// Configure the view.
let scene = GameMenuScene()
let skView = self.view! as SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.size = skView.bounds.size
scene.scaleMode = .AspectFill
skView.presentScene(scene, transition: transition)
})]))
}
}
When I initially launch the app, I can transition from scene 1 to scene 2. when the game is over, the app transitions back to scene 1. BUT when I try to go to scene 2 again, the app crashes. This only happens on a device, on the simulator, i can go back and forth without any problems.
the error I get is that a SKNode is being added that already exists. I know what it means and the error starts when I try to
// Add mainlayer & labelHolderLayer
self.addChild(mainLayer)
self.addChild(labelHolderLayer)
But I don't see why It can add the background with no problem but crash from there on. Also why does it work on the simulator but not on a device? do I really need to check in my didMoveToView if the nodes are already created?
I found out the mistake I was making.
I was instantiating the nodes outside my scene 2 class, making them global. Therefore when I went from scene 1 -> scene 2 -> scene 1 there was not problem but going then to scene 2 again caused a crash because the nodes were globally created.
Solution:
Moving the following code within the class solved the problem.
var mainLayer = SKSpriteNode()
var labelHolderLayer = SKSpriteNode()
var livesDisplay = SKSpriteNode()
var scoreLabel = SKLabelNode()