Alan Baumgartner
Alan Baumgartner

Reputation: 103

Consistant and Smooth Movement Via Joystick

So this is the code I have placed in the touchesMoved function and all of works. I also have ways of stopping each animation and movement in other functions that are not posted here.

The problem I am having, and it was fairly obvious to me before I finished coding it is that the movement will stutter/jitter and it isn't the smoothness I was looking for. I also wanted to ask how I could limit the speed at which the sprite moves as right now you can see that it moves by variable "v" which is based on how far you move from the joystick.

My joystick works in a way where your initial touch is the "base" and where you move too is the new direction.

TLDR: How do I limit movement speed where the speed is currently based on variable "v" and make the movement more smooth?

    for touch in touches {
        let location = touch.location(in: self)

        let v = CGVector(dx: location.x - joystickMove.x, dy: location.y - joystickMove.y)
        let angle = atan2(v.dy, v.dx)
        deg = angle * CGFloat(180/M_PI)
        readyToMove = true


        switch(deg){

        case -44...45:
            player.walkRight()
            let action = SKAction.moveBy(x: v.dx, y: v.dy, duration: 0.5)
            let repeatAction = SKAction.repeatForever(action)
            player.run(repeatAction, withKey: "move")
            break;
        case 46...135:
            player.walkUp()
            let action = SKAction.moveBy(x: v.dx, y: v.dy, duration: 0.5)
            let repeatAction = SKAction.repeatForever(action)
            player.run(repeatAction, withKey: "move")
            break;
        case 136...180, (-180)...(-135):
            player.walkLeft()
            let action = SKAction.moveBy(x: v.dx, y: v.dy, duration: 0.5)
            let repeatAction = SKAction.repeatForever(action)
            player.run(repeatAction, withKey: "move")
            break;
        case (-134)...(-45):
          player.walkDown()
            let action = SKAction.moveBy(x: v.dx, y: v.dy, duration: 0.5)
            let repeatAction = SKAction.repeatForever(action)
            player.run(repeatAction, withKey: "move")
            break;
        default:

            break;
        }
}

Upvotes: 0

Views: 129

Answers (2)

Stefan
Stefan

Reputation: 5451

The jittering is caused by the SKActions each runs 0.5 seconds. In the meanwhile multiple other touch events can happen which can trigger multiple other movements. You are also adding everytime new actions to the sprite which repeats forever.

I would move the animation to the update method:

var lastUpdateTime = TimeInterval()
var yourSpriteSpeed: CGFloat = 100.0
override func update(_ currentTime: TimeInterval) {

    let dt = CGFloat(currentTime - lastUpdateTime)
    lastUpdateTime = currentTime

    player.position = CGPoint(x: player.position.x + dx * yourSpriteSpeed * dt, y: player.position.x + dy * yourSpriteSpeed * dt)


}

Upvotes: 1

Benzi
Benzi

Reputation: 2459

To limit a vector v to a specific magnitude, you need to check if its magnitude exceeds the threshold and then normalise it.

Pseudocode:

func mag(v) -> Double {
    return sqrt(v.x * v.x + v.y * v.y)
}

func mult(v, amount) -> Vector {
    return Vector(v.x * amount, v.y * amount)
}

func div(v, amount) -> Vector {
    return Vector(v.x / amount, v.y / amount)
}

func unit(v) -> Vector {
    return  v.div(mag(v))
}

So now you do:

// ... compute v as before

if mag(v) > MAX_SPEED {
    v = unit(v).mult(MAX_SPEED)
}

// use v.x, v.y as before

While this approach will limit your joystick speed, I doubt it will completely rid you of your jitter issues (it just scales it back to the amount at MAX_SPEED).

PS: To get completely smooth motion, you need to maintain position and velocity as separate variables, and have a notion of a target velocity controlled by your joystick. At every frame, you update position based on current velocity and lerp current velocity to target velocity.

Abrupt changes in velocity is what causes jitters; lerping is one way to smoothen it out.

Upvotes: 0

Related Questions