为什么在场景之间来回转换时SpriteKit会崩溃

时间:2015-04-25 23:50:46

标签: ios swift sprite-kit sknode

我在这里和其他网站上查了答案,但没有得到明确的解决方案。

我有两个场景

场景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)

        }
    }
}

}

场景2:

类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)

    })]))

}

}

当我最初启动应用程序时,我可以从场景1转换到场景2.当游戏结束时,应用程序转换回场景1.但是当我再次尝试转到场景2时,应用程序崩溃了。这只发生在设备上,在模拟器上,我可以来回移动而没有任何问题。

我得到的错误是正在添加已存在的SKNode。我知道这意味着什么,当我尝试

时错误就开始了
    // Add mainlayer & labelHolderLayer
    self.addChild(mainLayer)
    self.addChild(labelHolderLayer)

但我不知道为什么它可以添加背景而没有任何问题,但从那里崩溃。另外为什么它可以在模拟器上工作,但不能在设备上工作?如果节点已经创建,我真的需要检查我的didMoveToView吗?

1 个答案:

答案 0 :(得分:1)

我发现了我犯的错误。

我正在实例化我的场景2类之外的节点,使它们成为全局的。因此当我从场景1开始 - &gt;场景2 - &gt;场景1没有问题,但是再次进入场景2导致崩溃,因为节点是全局创建的。

<强>解决方案:

在类中移动以下代码解决了问题。

var mainLayer = SKSpriteNode()
var labelHolderLayer = SKSpriteNode()
var livesDisplay = SKSpriteNode()
var scoreLabel = SKLabelNode()