0
votes

I have the following code in a pong paddle game in the GameViewController:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        let location = touch.location(in: self)

        main.run(SKAction.moveTo(x: location.x,duration: 4), completion: {
           print( "COMPLETED TOUCH BEGAN")
        })
    }
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        let location = touch.location(in: self)

        main.run(SKAction.moveTo(x: location.x,duration: 1), completion: {
            print( "COMPLETED TOUCH MOVED")
        })
    }
}

For some reason, when the duration of touchesBegan is greater than the duration of touchesMoved, my player will complete the touchesMoved actions first (even though touchesBegan had to come first), and then jump to a different x-position and then move with duration 4 to complete the touchesBegan. It's almost like the player reaches the position designated in touchesMoved (which should be almost exactly identical to the position in touchesBegan), goes back a somewhat arbitrary amount, and then moves to touchesBegan position. Is there a reason why it's jumping back and then moving like so?

My hypothesis is that for some reason, the touchesMoved actions are ran concurrently, and when they finish, the position jumps back to where it is slowly moving in touchesBegan and completes that movement to completion - almost like there are two objects moving at different rates with the slower one coming up after the faster one finishes. Is this at all correct? If so, why is it like this?

Edit:

I see that when I make the paddle move to one side of the screen, then tap on the opposite end of the screen and slide over, it will move to the final position that I released at, and then jump and move to where I first pressed. It's almost like the first action is playing in the background. The strange thing is if I hold my finger down (keeping the touchesMoved method called) until the movement in the touchesBegan finishes (so here it's 4 seconds), it doesn't jump to the other side of the screen!

In summary, I have multiple SKActions running with different durations, and from my observation, the priority is over the most recent action added to the action array. But instead of playing multiple actions over each other, the object jumps to different places on the screen to complete the final action.

1
What are you trying to achieve? You are creating many conflicting actions in a very short period of time. - nathangitter
@nathan I was actually following along with this tutorial and figured that what he was doing is normal. I'm completely new to SpriteKit. Either way, I'm curious now as to what exactly is going on. - rb612

1 Answers

0
votes

If you set up a second SKAction moving the same node, the second one doesn't cancel out the first. Rather, the position of the node is calculated after every frame based on all SKActions running. If the SKActions have the same duration and run at the same time, the last SKAction to run will always win out. For example:

// Same duration, node finishes at 100
main.run(SKAction.moveTo(x: -100, duration: 2)) //first to run
main.run(SKAction.moveTo(x: 100, duration: 2))  //second to run

If the first SKAction has a greater duration however, after the second SKAction has finished the position will only be calculated based on the first SKAction, for example:

//First SKAction's duration is longer, node finishes at -100
main.run(SKAction.moveTo(x: -100, duration: 3))
main.run(SKAction.moveTo(x: 100, duration: 2))

That's the reason why you're seeing the 'jump'.

SKAction documentation:

A node can run multiple actions simultaneously, even if those actions were executed at different times. The scene keeps track of how far each action is from completing and computes the effect that the action has on the node. For example, if you run two actions that move the same node, both actions apply changes to every frame. If the move actions were in equal and opposite directions, the node would remain stationary.

In your code touchesMoved can be called many times, and each time it is adding another SKAction to the node. I recommend you remove all actions on the main node before running another SKAction:

main.removeAllActions()

So in the end it will be:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        let location = touch.location(in: self)
        main.removeAllActions()
        main.run(SKAction.moveTo(x: location.x,duration: 4), completion: {
            print( "COMPLETED TOUCH BEGAN")
        })
    }
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        let location = touch.location(in: self)
        main.removeAllActions()
        main.run(SKAction.moveTo(x: location.x,duration: 1), completion: {
            print( "COMPLETED TOUCH MOVED")
        })
    }
}