iosanimationaudiosprite-kitskaction

Sprite Kit Animation timed to various sound files - GOAL: animation auto ends at end of each sound file to avoid manually timing each one


Hello! First question ever asked here!

I have a SpriteKit project with a variety of characters and sounds.

The characters are animated to a whole mess of varying sounds based on the scenes.

I am trying to find a way that the animations will end when the sound file completes playing. Currently I am using the following setup which would involve manually calculating the count for each scenario.

func animateCharacter() {
       
        let soundAction = SKAction.playSoundFileNamed("sound", waitForCompletion: false)
        let animateAction = SKAction.repeat(SKAction.animate(with: animatedFrames, timePerFrame: 0.1, resize: false, restore: true), count: 3)
        
        character.run(SKAction.sequence([soundAction,animateAction]))
        
        }

Is there any way to automate this so that each animation repeats for the length of each sound file?

I've tried using repeatForever along with removeAllActions - but that didn't seem to work?

I'm pretty green here but I'm guessing a type of completion handler based on audio file length?

Please help.

Thanks!

Brought to you by Carl's Jr.


Solution

  • You were right to use repeatForever and removeAllActions, a few amendments are needed though.

    Amend your animateAction, you want to use the repeatForever rather than counting manually, so change this:

    let animateAction = SKAction.repeat(SKAction.animate(with: animatedFrames, timePerFrame: 0.1, resize: false, restore: true), count: 3)
    

    To this:

    let animateAction = SKAction.repeatForever(SKAction.animate(with: animatedFrames, timePerFrame: 0.1, resize: false, restore: true))
    

    You can run your animate action at this point also, so add this on the row below it:

    character.run(animateAction)
    

    Your soundAction needs to have waitForCompletion set to true, as per the docs: If true, the duration of this action is the same as the length of the audio playback. If false, the action is considered to have completed immediately. You will notice that both your sound and animation run at the same time, even though you put SKAction.sequence.

    Your sound action should look like this:

    let soundAction = SKAction.playSoundFileNamed("sound", waitForCompletion: true)
    

    Because your wait for completion is now true, we can run the audio then remove actions once the audio has completed like this:

      character.run(soundAction) { [self] in
        character.removeAllActions()
      }
    

    SUMMARY

    This is the final code:

      let animateAction = SKAction.repeatForever(SKAction.animate(with: animatedFrames, timePerFrame: 0.1, resize: false, restore: true))
      character.run(animateAction)
      
      let soundAction = SKAction.playSoundFileNamed("sound", waitForCompletion: true)
      character.run(soundAction) { [self] in
          character.removeAllActions()
      }