0

I have a game scene that consists of animations that occur in sync with the content of a song. One of the actions I'm trying to set up is in relation to the lyrics of the song which are displayed using an SKLabelNode. What I want to do is is toggle between two animations based on whether or not there are characters in the LabelNode (the singer stops "singing" and waits). I have this in the update method:

var singerActive = false
var lyricsLabel = SKLabelNode()

override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */
        if lyricsLabel.text?.characters.count == 0{
            singerActive = false
        }else{
            singerActive = true
        }

        let sings = SKAction.runBlock { () -> Void in
            self.singer.runAction(SKAction.fadeAlphaTo(1, duration: 0.1))
            self.singerIdle.runAction(SKAction.fadeAlphaTo(0, duration: 0.1))
        }
        let singerInactive = SKAction.runBlock { () -> Void in
            self.singer.runAction(SKAction.fadeAlphaTo(0, duration: 0.1))
            self.singerIdle.runAction(SKAction.fadeAlphaTo(1, duration: 0.1))
        }

        var stopper = true
        if singerActive && stopper{
            stopper = false
            singer.runAction(sings)
        }

        if singerActive == false && stopper == false{

            stopper = true
            singer.runAction(singerInactive)
        }

    }

Unfortunately, this doesn't seem to work. The active singer state works, but the inactive state fails to trigger when the character count == 0. I put the "stopper" bool in there in order to ensure that the SKAction doesn't get called continuously as it's in the update method. I'm fairly new to Swift and SpriteKit so any help would be greatly appreciated.

derekFairholm
  • 285
  • 1
  • 14
  • here is what I am seeing. when inactive, your first condition fails, so stopper never changes, thus your second condition fails, because stopper is always true – Knight0fDragon Feb 18 '16 at 22:20

1 Answers1

1

Your stopper code is breaking everything, you want to do something like this:

    override func update(currentTime: CFTimeInterval) {
    /* Called before each frame is rendered */
    if lyricsLabel.text?.characters.count == 0{
        singerActive = false
    }else{
        singerActive = true
    }

    let sings = SKAction.runBlock { () -> Void in
        self.singer.runAction(SKAction.fadeAlphaTo(1, duration: 0.1))
        self.singerIdle.runAction(SKAction.fadeAlphaTo(0, duration: 0.1))
    }
    let singerInactive = SKAction.runBlock { () -> Void in
        self.singer.runAction(SKAction.fadeAlphaTo(0, duration: 0.1))
        self.singerIdle.runAction(SKAction.fadeAlphaTo(1, duration: 0.1))
    }

    if singerActive{
        singer.removeAllActions()
        singer.runAction(sings)
    }
    else{
        singer.removeAllActions()
        singer.runAction(singerInactive)
    }

}

But this is also bad because this means that you are always running an action on every update. You may want to rework your code so this isn't happening.

So you need to do something like this:

    override func update(currentTime: CFTimeInterval) {
    /* Called before each frame is rendered */
    if lyricsLabel.text?.characters.count == 0{
        singerActive = false
    }else{
        singerActive = true
    }

    let sings = SKAction.runBlock { () -> Void in
        self.singer.runAction(SKAction.fadeAlphaTo(1, duration: 0.1))
        self.singerIdle.runAction(SKAction.fadeAlphaTo(0, duration: 0.1))
    }
    let singerInactive = SKAction.runBlock { () -> Void in
        self.singer.runAction(SKAction.fadeAlphaTo(0, duration: 0.1))
        self.singerIdle.runAction(SKAction.fadeAlphaTo(1, duration: 0.1))
    }

    if singerActive && singerIdle.alpha = 1{
        singer.removeAllActions()
        singerIdle.alpha = 0.99;
        singer.runAction(sings)
    }
    else if !singerActive && singer.alpha = 1{
        singer.removeAllActions()
        singer.alpha = 0.99;
        singer.runAction(singerInactive)
    }

}

Now we only call it when our alpha states are at 1

Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • Great, thanks! This works well, except I needed to delete the removeAllActions() method...each animation is continuously running and I just change the alpha states to make the desired animation visible. – derekFairholm Feb 19 '16 at 20:05
  • if you do not removeAllActions then they will build up on you, I am assuming this code is going so fast that removeAllActions is removing actions before it does anything – Knight0fDragon Feb 19 '16 at 20:06
  • Is there some way to do at least the skactions outside of update? It seems like there must be a cleaner way of handling this... – derekFairholm Feb 20 '16 at 04:18
  • not sure what you are going for here, but there are a few ways you can go about doing it outside of your update, I just wasn't going to rewrite your code. You could add a listener to when label text changes, or you could create a string property and use `didSet` to run actions when a new word appears/disappears , then assign this string property to text – Knight0fDragon Feb 20 '16 at 04:24
  • Would you mind explaining adding a "listener"? Pretty new to this, much appreciated. – derekFairholm Feb 20 '16 at 04:34
  • http://www.raywenderlich.com/90773/introducing-ios-design-patterns-in-swift-part-2 look at key-value observing – Knight0fDragon Feb 20 '16 at 04:39