Search code examples
swiftsprite-kitgamecontroller

Moving skspritenode with Game Controller (ThumbStick) Swift


I try to build 2d - top down game, and I have player(skspritenode) and I want to move him when I use the thumbstick. I use this code:

gamepad its GCExtendedGamepad

if gamepad.leftThumbstick.xAxis.value > 0.1 || gamepad.leftThumbstick.xAxis.value < -0.1 || gamepad.leftThumbstick.yAxis.value > 0.1 || gamepad.leftThumbstick.yAxis.value < -0.1
{
    self.player.moveAndRotate(gamepad.leftThumbstick.xAxis.value, yValue: gamepad.leftThumbstick.yAxis.value)
}

moveAndRotate - function

func moveAndRotate(xValue: Float, yValue: Float)
{
    zRotation = CGFloat(-atan2(xValue, yValue))

    physicsBody!.velocity = CGVectorMake(0, 0)
    physicsBody!.applyImpulse(CGVectorMake(CGFloat(xValue) * moveSpeed, CGFloat(yValue) * moveSpeed))
}

But, when player moves by diagonal, his speed faster than normal speed. Can anyone help me?


Solution

  • I am sure that your trig functions is backwards

    Here is snippet of code I use in a game to move diagonally.

    let angle: CGFloat = atan2f(dest.y - self.position.y, dest.x - self.position.x)
    

    The y value comes before the x value

    Quoted from Raywenderlich.com

    For this specific problem, instead of using atan(), it is simplier to use the function atan2(), which takes the x and y components as separate parameters, and correctly determines the overall rotation angle.

    angle = atan2(opposite, adjacent)
    
    let angle = atan2(playerVelocity.dy, playerVelocity.dx)
    playerSprite.zRotation = angle
    

    Notice that the Y-coordinate goes first. A common mistake is to write atan(x, y), but that’s the wrong way around. Remember the first parameter is the opposite side, and in this case the Y coordinate lies opposite the angle you’re trying to measure.

    new I was able to recreate your issue, but by changing the code to the below I was able to have diagonal move a the same speed as up and down

    if ((!isDPad && dirPad.up.value > 0.2) || (isDPad && dirPad.up.pressed == true)) { self.upValue = 1 //upValue = gamepad.leftThumbstick.up.value }

        if ((!isDPad && dirPad.down.value > 0.2) || (isDPad && dirPad.down.pressed == true)) {
            self.downValue = 1
        }
    
        if ((!isDPad && dirPad.right.value > 0.2) || (isDPad && dirPad.right.pressed == true)) {
            self.rightValue = 1
        }
    
        if ((!isDPad && dirPad.left.value > 0.2) || (isDPad && dirPad.left.pressed == true)) {
            self.leftValue = 1
        }
    
        let speed: Float = 300.0
        let xValue = self.rightValue - self.leftValue
        let yValue = self.upValue - self.downValue
    
        let length = hypotf(xValue, yValue)
    
        var moveDirection: CGVector?
    
        if length > 0.0 {
            let inverseLength = 1 / length
            moveDirection = CGVector(dx: CGFloat(xValue * inverseLength * speed), dy: CGFloat(yValue * inverseLength * speed))
        }
        else {
            moveDirection = CGVector(dx: 0, dy: 0)
        }
    
        testObject.physicsBody!.velocity = CGVectorMake(0, 0)
        testObject.physicsBody!.applyImpulse(direction)