Jean Valjean
Jean Valjean

Reputation: 736

Swift: Checking progress on SKActions

I have a couple sprites in a swift game that have identical action lists (technically [SKAction]). They're all at different points in the action sequence, and I need to rank them in order of most complete (with the action) to least complete. How do I get the progress of a sprite (or at least the step of the action it's on)? Preferably, I'd like to get the percentage of completion for the step it's on.

For the sake of sample code:

    let sprite1 = SKShapeNode.init(rectOf: CGSize.init(width: 20, height: 20), cornerRadius: 5)
    let sprite2 = SKShapeNode.init(rectOf: CGSize.init(width: 20, height: 20), cornerRadius: 5)
    let sprite3 = SKShapeNode.init(rectOf: CGSize.init(width: 20, height: 20), cornerRadius: 5)

    sprite1.position = CGPoint(x: -100, y: 0)
    sprite2.position = CGPoint(x: 0, y: 0)
    sprite3.position = CGPoint(x: 100, y: 0)

    let sequence : [SKAction] = [SKAction.move(by: CGVector(dx: 50, dy: 0), duration: 1.5),
                                 SKAction.rotate(byAngle: CGFloat(M_PI / 2), duration: 1.0),
                                 SKAction.move(by: CGVector(dx: 0, dy: 50), duration: 1.5),
                                 SKAction.rotate(byAngle: CGFloat(M_PI / 2), duration: 1.0),
                                 SKAction.move(by: CGVector(dx: -50, dy: 0), duration: 1.5)]

    sprite1.run(SKAction.sequence(sequence))
    //wait 1 second
    sprite2.run(SKAction.sequence(sequence))
    //wait another second
    sprite3.run(SKAction.sequence(sequence))

    var spriteAccord : [SKSpriteNode] = //insert ranking code

Upvotes: 0

Views: 174

Answers (2)

Knight0fDragon
Knight0fDragon

Reputation: 16837

As long as the speed of the sprite is constant (AKA no bullet time effect) I would just use a dictionary to store starting times:

var startingTimes = [SKNode:NSTimeInterval]()

Then store when a sprite starts his sequence

sprite1.run(SKAction.sequence(sequence))
startingTimes[sprite1 as! SKNode] = currentTime

Finally, sort by the startingTime

let sortedStartingTimes = startingTimes.sort(){
                          (time1,time2)->Bool in 
                          return time1 <= time2
                      }

Then, just iterate through the dictionary, or grab the first item, whatever you need to do here.

This can be popped into playgrounds to test the above code:

var startingTimes = [String:NSTimeInterval]()
startingTimes["A"] = 1
startingTimes["C"] = 3
startingTimes["B"] = 2

let sortedStartingTimes = startingTimes.sort(){
    (time1,time2)->Bool in
    return time1 <= time2
}
print("start")
for time in startingTimes
{
    print(time)
}
print("sort")
for time in sortedStartingTimes
{
    print(time)
}

To get the percentage of completion is a little more complex. You need to take your currentTime - startingTime, then figure out based on this where you are at in your sprite.

So I have a total of 3 steps, each 1 second.

My currentTime - startingTime is 1.5 seconds.

var deltaTime = currentTime - startingTime

I take 1.5 - step 1 time, so result is .5 seconds

deltaTime -= step1Time

deltaTime > 0, I am in a new step

I take .5 - step 2 time, so result is .5 seconds

deltaTime -= step2Time

deltaTime <= 0 I am in this step

so deltaTime / step2time , that is my percentage in the step2 timeline

  let completionPercentage = deltaTime / step2Time

Upvotes: 1

Ali Beadle
Ali Beadle

Reputation: 4526

You can insert runBlock actions between your existing actions. In the block you can then increment counters to track the progress of each node through the actions.

Upvotes: 1

Related Questions