1
votes

Ok, so I have an array of Cgpoints that I move a sprite node to as I iterate through the array. The sprites distance from the next point varies with each point

func moveGuy() {
    let action = SKAction.move(to: points[i], duration: 2)
    action.timingMode = .easeInEaseOut
    guy.run(action)   
}

//UPDATE
override func update(_ currentTime: CFTimeInterval) {
    if(mouseIsDown)
    {
       moveGuy()
    }
}

My problem is with a static duration, depending on where the sprite is he moves at a slower/faster speed. No matter the distance sprite must travel I need to have constant speed.

How can I vary an SKAction speed based on sprite's distance from end point?

2

2 Answers

3
votes

That would require using the distance formula. Now to maintain a constant speed, you need to determine points per second (pps) you want to move.

Basically the formula becomes distance/pps

So let's say we want to travel (0,0) to (0,300) (This is 300 points so it should take us 2 seconds)

pseudo code:

let duration = sqrt((0 - 0) * (0 - 0) + (0 - 300) * (0 - 300)) / (150)
duration = sqrt(90000) / (150)
duration = 300 / 150
duration = 2

You would then pop it into your move action:

let action = SKAction.move(to: points[i], duration: duration)

Your Swift code should look something like this:

let pps = 150 //define points per second
func moveGuy() {
    var actions = [SKAction]()
    var previousPoint = guy.position // let's make sprite the starting point
    for point in points
    {
      //calculate the duration using distance / pps
      //pow seems to be slow and some people have created ** operator in response, but will not show that here
      let duration = sqrt((point.x - previousPoint.x) * (point.x - previousPoint.x) + 
                     (point.y - previousPoint.y) * (point.y - previousPoint.y)) / pps

      //assign the action to the duration
      let action = SKAction.move(to: point, duration: duration)
      action.timingMode = .easeInEaseOut
      actions.append(action)
      previousPoint = point
    }   
    guy.run(actions)
}

//Since the entire path is done in moveGuy now, we no longer want to be doing it on update, so instead we do it during the mouse click event
//I do not know OSX, so I do not know how mouse down really works, this may need to be fixed
//Also I am not sure what is suppose to happen if you click mouse twice,
//You will have to handle this because it will run 2 actions at once if not done
override func mouseDown(event:NSEvent)
{
    moveGuy()
}

Now you will notice your sprite running up and slowing down at every iteration, you may not want that, so for your timing mode, you may want to do this instead

//Use easeInEaseOut on our first move if we are only moving to 1 point
if points.count == 1
{
    action.timingMode = .easeInEaseOut
}
//Use easeIn on our first move unless we are only moving to 1 point
else if previousPoint == sprite.position
{
    action.timingMode = .easeIn
}
//Use easeOut on our last move unless we are only moving to 1 point
else if point == point.last
{
    action.timingMode = .easeOut
}
//Do nothing
else
{
    action.timingMode = .linear
}
0
votes

You will have to create a new SKAction with a duration calculated from the distance to move and the speed (in points/s) of the node to be moved.