Search code examples
swiftsprite-kitsknode

Swift: Attemped to add a SKNode which already has a parent:


I know why I'm getting that error, but I can't figure out a way around it. I'm trying to have objects come appear and then be removed and the player should try to tap them before they're removed, but everytime the next node is about to appear it crashes. If i declare it inside its func then it all comes out but I can't tap on it...

Code:

let step = SKSpriteNode()

override func didMoveToView(view: SKView) {
    physicsWorld.contactDelegate = self
    backgroundColor = UIColor.feelFreeToColor()

    self.color = self.randomNumbersInt(3)
    self.showBars()
    self.showScore()
    let spawn = SKAction.runBlock {
        //self.color = self.randomNumbersInt(3)
        self.showSteps()
    }
    let delay = SKAction.waitForDuration(1.5)
    let spawnDelay = SKAction.sequence([spawn , delay])
    let spawnDelayForever = SKAction.repeatActionForever(spawnDelay)

    self.runAction(spawnDelayForever)
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch in touches {
        var location = touch.locationInNode(self)

        if self.nodeAtPoint(location) == step {
            self.score += 1
        }
    }
}

func showSteps() {
    let createSteps = SKAction.moveByX(0, y: -self.frame.height - 30 , duration: 10)
    let removeSteps = SKAction.removeFromParent()

    step.color = colors[randomNumbersInt(3)]!
    step.size = CGSize(width: 275, height: 30)
    step.position = CGPoint(x: self.frame.width * 0.5, y: self.frame.height * 0.75)
    step.physicsBody = SKPhysicsBody(rectangleOfSize: step.size)
    step.physicsBody?.categoryBitMask = Config.PhysicBodyType.Steps.rawValue
    step.physicsBody?.affectedByGravity = false
    step.physicsBody?.dynamic = false
    step.zPosition = 1
    step.runAction(SKAction.repeatActionForever(SKAction.sequence([createSteps, removeSteps])))

    addChild(step)
}

Solution

  • In your showSteps function, declare the step node inside it, not at the top of your code, and also give it a name:

    func showSteps() {
        let step = SKSpriteNode()
        ...
        step.name = "step"
        step.color = colors[randomNumbersInt(3)]!
        // etc
    }
    

    In your touchesBegan method, you have this if statement:

    if self.nodeAtPoint(location) == step {
         self.score += 1
    }
    

    You want to remove that node that you have hit, but now you can just check the name property like so:

    if self.nodeAtPoint(location)?.name == "step" {
        self.nodeAtPoint(location)?.removeFromParent()
        self.score += 1
    }
    

    Please note that I am not super fluent in Swift, but I think you will probably need the ? in your if statement, as it might not exist (such as if you didn't tap on a specific node). Somebody more familiar with Swift is free to correct me.