arraysswiftfor-loopskactionaddchild

Time delay for addChild in for loop is causing error! Swift


This loop I have works fine, but I want to have the images from the arrays come in one after the other with a specific set amount of time between them.

if transitionSprite.name == nil || transitionSprite.name == "rd-d2c" || transitionSprite.name == "rd-f2c" {
        for (index, roadImage) in cityArrays[randomIndex].enumerated() {

            roadSprite = SKSpriteNode(imageNamed: roadImage)
            roadSprite.anchorPoint = CGPoint(x: 0.5, y: 0.5)
            roadSprite.position = CGPoint(x: 0, y: CGFloat(screenCounter) * roadSprite.size.height)
            roadSprite.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: self.size.width, height: self.size.height))
            roadSprite.physicsBody?.categoryBitMask = PhysicsCategory.RoadImageCategory.rawValue
            roadSprite.physicsBody?.collisionBitMask = PhysicsCategory.NoCollisionsCategory.rawValue
            roadSprite.physicsBody?.contactTestBitMask = PhysicsCategory.BroomCategory.rawValue
            roadSprite.physicsBody?.affectedByGravity = false

            roadSprite.zPosition = 1
            roadSprite.name = "Road \(index)"

            // RUNNING THE SKACTION DELAY ON THIS
            self.addChild(roadSprite)

            addCollectables()
            addJerryCans()

            if roadImage == "rdc-02_05" {
                addBackgroundDetail(detailType: "cityBridge2")
            }
            screenCounter += 1
        }

I've created this SKAction which I've added to the loop,

    loopDelay = SKAction.wait(forDuration: Double(index + 1))
    let addRoad = SKAction.run {self.addChild(self.roadSprite)}
    let action = SKAction.sequence([loopDelay, addRoad])
    self.run(action)

Not sure what would cause this, but when I run it with the SKAction delay I've created it crashes and gives me this error,

Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'Attemped to add a SKNode which already has a parent: 
<SKSpriteNode> name:'Road 4' texture:[<SKTexture> 'rdc-02_05' (750 x 
1334)] position:{0, 6670} scale:{1.00, 1.00} size:{750, 1334} 
anchor:{0.5, 0.5} rotation:0.00'

Any ideas of why the delay would be causing this? Thanks


Solution

  • Your problem is that you store roadSprite using a property. So at each iteration of the for-in loop you replace what's stored in that property with a new Sprite.

    When each delay passes they will all try to addChild using the same Sprite (which is the last one you created), hence the first time it gets added and the second time it gives you the error above: "Attempted to add a SKNode which already has a parent".

    What you want here is to create the sprite as a local variable instead and capture that variable in the SKAction.run closure:

    let roadSprite = SKSpriteNode(imageNamed: roadImage)
    
    ...
    
    let addRoad = SKAction.run {self.addChild(roadSprite)} //capture the local variable in your closure here
    

    If you still want a reference to all of these Sprites then maybe you should stick them into an array instead of overriding the same property.