8
votes

Playing around with SKSprites in the IOS SpriteKit, and I basically want to have a sprite randomly move a certain direction for a certain distance, then pick a new random direction and distance.. Simple enough, create a method that generates the random numbers then creates the animation and in the completion block of the animation have it callback the same routine.

THis does work, but it also keeps the animation from moving at the same velocity since the animations are all based on duration.. If the object has to move 100 it moves at 1/2 the speed it moves if the next random tells it to move 200... So how the heck do I have it move with a consistent speed?

3
You should post the code you’re using to determine (and animate to) the new position. The basic answer to your question is that the animation’s duration should be a fixed multiple of the distance between the current and next location, but it’d be easier to explain that with a modification of your current code.Noah Witherspoon
I did do this, and while it does work, it just seems kludgy, I would think there could be something along the lines of move to xy with speed instead of everything being duration based.Speckpgh
This sort of model, where you calculate duration per pixel moved, then multiplying it by how many you need to move, needs to do things like take into account if you are moving x and y at the same time since 1 pixel diagonal is actually a larger distance than 1 pixel left and right, (square root of 2 vs 1) assuming the pixels themselves are actually square.Speckpgh
The API doesn’t have anything like that at the moment, but you’re free to file an enhancement request asking for it. The solution to handling distances in X and Y at the same time is to use the Pythagorean theorem.Noah Witherspoon
Thanks, yes I know how to calculate for the angular speeds, just find it a bit kludy that's all. I understand the api is written around durations, not speed, but seems if we are trying to capture physics that velocity and distance might be a better model than simply distance and time.Speckpgh

3 Answers

14
votes

@Noah Witherspoon is correct above - use Pythagorus to get a smooth speed:

//the node you want to move
SKNode *node = [self childNodeWithName:@"spaceShipNode"];

//get the distance between the destination position and the node's position
double distance = sqrt(pow((destination.x - node.position.x), 2.0) + pow((destination.y - node.position.y), 2.0));

//calculate your new duration based on the distance
float moveDuration = 0.001*distance;

//move the node
SKAction *move = [SKAction moveTo:CGPointMake(destination.x,destination.y) duration: moveDuration];
[node runAction: move];
4
votes

Using Swift 2.x I've solved with this little method:

func getDuration(pointA:CGPoint,pointB:CGPoint,speed:CGFloat)->NSTimeInterval {
    let xDist = (pointB.x - pointA.x)
    let yDist = (pointB.y - pointA.y)
    let distance = sqrt((xDist * xDist) + (yDist * yDist));
    let duration : NSTimeInterval = NSTimeInterval(distance/speed)
    return duration
}

With this method i can use an ivar myShipSpeed and directly call my actions for example :

let move = SKAction.moveTo(dest, duration: getDuration(self.myShip.position,pointB: dest,speed: myShipSpeed))
self.myShip.runAction(move,completion: {
  // move action is ended
})
3
votes

As an extension to @AndyOS's answer, if you're going to move only along one axis (X for example) you can simplify the math by doing this instead:

CGFloat distance = fabs(destination.x - node.position.x);