Stopwatch and grouping animation

I am making a death animation for a game and I want to ask for help. I want my monster to disappear into the haze, but not before it animates the effect of the forward slash running through its body.

I have 3 animations that I want to use:

weaponSlash - the line that draws the monster. It looks like you destroyed him with your sword.

smoke - a layer of smoke that slowly expands

monster Falling - the monster falls, hit

I want to do it in the following order:

  • At the same time, a slash appears and the monster begins to fall back
  • About 0.25s in the animation above, I want the cloud to start appearing
  • When the cloud is about to end (maybe after the 1st), I want the monster to disappear.
  • Remove smoke, monster, sword, etc., and drop some coins on the ground.

I started like this as a test that works somewhat: (ignore the times above for now)

 //Cancel any current actions, like a monster attacking
 monster.removeAllActions()

 //since you can't play 3 animations on one node at the same time, you have to create 3 separate nodes for everything                          
 let slash = SKSpriteNode()
 let cloud = SKSpriteNode()
 cloud.size = monster.size
 slash.size = monster.size
 monster.addChild(cloud)
 monster.addChild(slash)


 //Start the slash animation
 slash.run(self.player.currentlyEquippedWeapon.attackAnimation())

 //Start the cloud animation (how I get it is elsewhere and not relevant)
 cloud.run(cloudAnimation)

//Run the monster death animation, followed by the cleanup/coin dropping                   
monster.run(SKAction.sequence([monster.deathAnimation(), SKAction.wait(forDuration: 1), postDeathActions]))

      

The PostDeathActions variable above just removes the monster node and animates some coins falling.


WHERE I NEED SOME HELP

So the above code doesn't work so well that the animations work independently of each other. Based on this, you can see how no matter if the slash / cloud ends, the monster will do two things: it will step back and then clear, which will simply remove the monster and spread the coins. As you can see, I tried to delay this by adding a 1 second delay, but this is all like a hack, since I can have different monsters or attacks, etc. which are faster / slower. I'd rather it be over before I destroy the monster.

I tried to group this in SKAction.Run like so:

let preDeath = SKAction.run {
 [unowned self] in
   monster.run(monster.deathAnimation() 
   slash.run(self.player.currentlyEquippedWeapon.attackAnimation())
   cloud.run(cloudAnimation)
 }

      

but this starts everything up again at the same time.

What I want to do is order it like this (pseudocode):

let preDeathAnimations = SKAction.Group ([slash, cloud, monsterDeathAnimation])])

SKAction.sequence ([preDeathAnimations, postDeathActions])

This way it will run all 3 before starting cleanup.

Is there a way to do something like this? I know Sequnce / Group needs to be run against SKNode, but I don't have 3 separate ones.

Thanks for your time reading this and any tips you can offer!

+3


source to share


1 answer


This is one of the ideas I had, but you can use threading + state + onCompletion blocking to get the math out of it. I haven't fully tested it, but this general concept should work:

let slash = SKAction.fadeIn(withDuration: 0.5)

let fall = SKAction.fadeOut(withDuration: 0.25)

let puff = SKAction.fadeIn(withDuration: 0.1)

// Put in ALL of the actions from ALL parties that you want to happen prior to puff:
func findLongestTime(from actions: [SKAction]) -> TimeInterval {

  var longestTime = TimeInterval(0)

  for action in actions {
    if action.duration > longestTime { longestTime = action.duration }
  }

  // Note, if you put a sequence into this function I don't know if it will work right..
  // Might need another func like `findDurationOfSequence(_ sequence: SKAction) -> TimeInterval
  return longestTime
}

// Note, if you have the monster doing more than falling prior to puff, then you will
// need to subtract those as well:
let monsterActionsPriorToPuff = [fall]

// Add the duration of all monster animations prior to puff:
var MAPTP_duration = TimeInterval(0)
for action in monsterActionsPriorToPuff {
  MAPTP_duration += action.duration
}

// Calculate our final wait time, with no negative numbers:
  var waitTime = findLongestTime(from: [slash, fall]) - MAPTP_duration
if waitTime < 0 { waitTime = 0 }
let wait = SKAction.wait(forDuration: waitTime)

// Our monster sequence (I forgot to add the disappear, just add after puff)
let monsterSequence = SKAction.sequence([fall, wait, puff])

// Player slashes:
SKSpriteNode().run(slash)

// Monster will wait 0.25 seconds after falling,
// for slash to finish before puffing:
SKSpriteNode().run(monsterSequence)

      




et me know, if this idea doesn't work, I can try to update it.

+1


source







All Articles