Search code examples
swiftxcodesprite-kitswift4

Move Sprite Based Off of Degrees


I've been able to detect degrees, but I'm unsure on how to move the sprite in 360 degrees. drawing I don't want the sprite to be able to only move in certain sections, as shown in the picture above, but rather have it be able to move in a full circle. Code:

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

        if (ball.frame.contains(location)) {

            stickActive = true
        }else {

            stickActive = false

        }

    }

}

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

        if (stickActive == true) {


            var v = CGVector(dx: location.x - base.position.x, dy: location.y - base.position.y)
            let angle = atan2(v.dy, v.dx)
            var deg = angle * CGFloat(180 / M_PI)
            print(deg + 180)

            let lenght:CGFloat = base.frame.size.height / 2 - 20
            let xDist: CGFloat = sin(angle - 1.57079633) * lenght
            let yDist: CGFloat = cos(angle - 1.57079633) * lenght
            ball.position = CGPoint(x: base.position.x - xDist, y: base.position.y + yDist)

            if (base.frame.contains(location)) {

                ball.position = location
            }else {

                ball.position = CGPoint(x: base.position.x - xDist, y: base.position.y + yDist)

            }

        }

    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if (stickActive == true) {


        let move: SKAction = SKAction.move(to: base.position, duration: 0.2)
        move.timingMode = .easeOut

        ball.run(move)


    }
}

Solution

  • This is super simple, although it took me quite awhile to figure out how to do it.

    TouchesBegan method:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location = touch.location(in: self)
            if isTracking == false && DPad.contains(location) {
                isTracking = true
            }
        }
    }
    

    TouchesMoved method:

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location: CGPoint = touch.location(in: self)
            if isTracking == true {
    
                v = CGVector(dx: location.x - DPad.position.x, dy: location.y - DPad.position.y)
                let angle = atan2(v.dy, v.dx)
                let deg = angle * CGFloat(180 / Double.pi)
    
                let Length:CGFloat = DPad.frame.size.height / 2
                let xDist: CGFloat = sin(angle - 1.57079633) * Length
                let yDist: CGFloat = cos(angle - 1.57079633) * Length
    
                xJoystickDelta = location.x - DPad.position.x
                yJoystickDelta = location.y - DPad.position.y
    
                if DPad.contains(location) {
                    thumbNode.position = location
                } else {
                    thumbNode.position = CGPoint(x: DPad.position.x - xDist, y: DPad.position.y + yDist)
                }
            }
        }
    }
    

    TouchesEnded method:

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        isTracking = false
        thumbNode.run(SKAction.move(to: DPad.position, duration: 0.01))
        xJoystickDelta = 0
        yJoystickDelta = 0
    }
    

    The update(_ currentTime:) method:

        if v.dx > abs(v.dy) {
            yourPlayer.texture = SKTexture(imageNamed: "rightTexture")
        } else if v.dx < -abs(v.dy) {
            player.texture = SKTexture(imageNamed: "leftTexture")
        } else if v.dy < 0 {
            yourPlayer.texture = SKTexture(imageNamed: "frontTexture")
        } else if v.dy > 0 {
            yourPlayer.texture = SKTexture(imageNamed: "backTexture")
        }
        //This code moves your character where-ever you want it too
        let xScale = CGFloat(4) //adjust to your preference. Higher means slower, lower means faster
        let yScale = CGFloat(4) //adjust to your preference. Higher means slower, lower means faster
    
        let xAdd = xScale * self.xJoystickDelta
        let yAdd = yScale * self.yJoystickDelta
    
        yourPlayerNode.position.x += xAdd
        yourPlayerNode.position.y += yAdd
    

    These things need to be outside your didMove(toView:) method:

    var xJoystickDelta:CGFloat = 0
    var yJoystickDelta:CGFloat = 0
    var v = CGVector()
    var isTracking:Bool = false
    
    var DPad = SKSpriteNode()
    var thumbNode = SKSpriteNode()
    

    -Explanation-

    In the touchesBegan method, the if-statement is testing to see if you are not controlling the thumbNode and if your touch is inside the DPad Node. Then it starts the tracking.

    In the touchesMoved once isTracking == true it starts calculating the neccessary math and then adjusting the various things required. (its complicated, what matters most is that it works.)

    In the touchesEnded method, it is testing to see when you lift your finger off of the screen, then it resets everything for the next usage.

    In the update(_ current:) method, the code is calculating the angle of the CGVector and then setting a texture (or whatever you want to do) inside of the various cases. Then its calculating the position of the thumbNode inside the DPad and moving your player (or whatever you need to move) around in the scene. Adjust the xScale and yScale floats higher to slow down the movement, and lower to increase the movement of whatever you are trying to move.

    -Extra neccessary stuff-

    You need to set up the DPad and thumbNode inside your didMove(toView:) method:

    thumbNode.size = CGSize(width: 50, height: 50)
    DPad.size = CGSize(width: 150, height: 150)
    DPad.position = CGPoint(x: 0, y: 0)
    thumbNode.position = DPad.position
    DPad.zPosition = 3
    thumbNode.zPosition = 4
    DPad.texture = SKTexture(imageNamed: "yourBaseTexture")
    thumbNode.texture = SKTexture(imageNamed: "yourStickTexture")
    
    self.addChild(thumbNode)
    self.addChild(DPad) 
    

    You only have to move the DPad.position to wherever you want. The thumbNode will move along with it. Also, if you have any problems be sure to ask me so I can help you.