Brejuro
Brejuro

Reputation: 3541

Waiting for SKAction completion inside a for loop

I have a for loop that runs 10 times, each time creating a node and adding it to the scene. However, I want there to be a delay in between each node being added (add a node, wait a second, add a node, wait a second, etc.)

However, after the first 1 second, all 10 nodes are added at the same time. How can I achieve this desired effect of waiting a second in between each node being added?

Here is my code:

EDIT:

func createText(correct: Bool) {
        let text = SKNode()
        var line: String!

        addChild(text)

        if correct {
            line = (GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(happyLines) as! [String])[0]
        } else {
            line = (GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(sadLines) as! [String])[0]
        }

        var xPos = self.frame.midX + 300
        var yPos = self.frame.midY

        var spaces = 1

        // For each character in sentence, create a node of it
        for character in line.characters {
        runAction(SKAction.waitForDuration(1.0)) {
            if spaces == 4 {
                spaces = 0
                print("space")
                xPos = self.frame.midX + 300
                yPos -= 30
            }

            xPos += 10

            if character != " " {
                let letter = SKLabelNode(fontNamed: GameScene.fontName)
                letter.fontSize = 14 * GameScene.fontScale
                letter.position = CGPoint(x: xPos, y: yPos)
                letter.text = String(character)
                text.addChild(letter)
            } else {
                spaces += 1
                xPos += 10
            }

        }
    }

        runAction(SKAction.waitForDuration(2.0)) {
            text.removeAllChildren()
            text.removeFromParent()
        }

    }

Upvotes: 2

Views: 711

Answers (2)

nathangitter
nathangitter

Reputation: 9795

You can achieve this using actions.

First, create actions for the delay and adding the node to the scene.

let waitAction = SKAction.wait(forDuration: 1)
let addNodeAction = SKAction.run {
    let node = SKSpriteNode(imageNamed: "example")
    self.addChild(node)
}

Next, create a sequence of actions so that the delay always occurs before the node is added to the scene.

let sequenceAction = SKAction.sequence([waitAction, addNodeAction])

Next, create an action that repeats the sequence 10 times.

let repeatAction = SKAction.repeat(sequenceAction, count: 10)

Finally, run this action and watch the nodes appear!

run(repeatAction)

EDIT:

To solve your second question in the comments about needing access to the current character (making each action where the node is added slightly different), loop through your characters to build a sequence of actions, and then run that action.

var actions = [SKAction]()

let waitAction = SKAction.wait(forDuration: 1)

for character in line.characters {

    let addNodeAction = SKAction.run {
        let node = SKSpriteNode(imageNamed: "example")
        // use the character variable here
        self.addChild(node)
    }

    actions.append(waitAction)
    actions.append(addNodeAction)

}

let sequenceAction = SKAction.sequence(actions)
run(sequenceAction)

Upvotes: 1

JohnV
JohnV

Reputation: 990

How about this? (not tested :)

for (i, character) in line.characters.enumerate() {
   runAction(SKAction.waitForDuration(Double(i) * 1.0)) {
       // rest of your for loop

So you enumerate through the characters, where i is the i-th character, starting at 0. With each character, you just multiply its index position in the string with the 1 second interval to give you the wait duration.

Upvotes: 1

Related Questions