Davis Mariotti
Davis Mariotti

Reputation: 605

Trouble converting between coordinate spaces in SpriteKit

I am trying to get a SKShapeNode to follow a UITouch

My problem is that the location of the UITouch is relative to the bottom-left corner of the screen and the position of the SKShapeNode is relative to the location I gave it when I created it, the center of the screen.

For example: ball is centered at (189.0, 335.0), the center of the view. I click the ball, the location of the touch tells me the touch event occurred at (189.0, 335.0), but the ball.position will tell me (0.0, 0.0). How can I get the ball's position in the view's coordinate system?

import SpriteKit
import GameplayKit

class GameScene: SKScene {

    var touched = false
    var location = CGPoint.zero
    var ball: SKShapeNode = SKShapeNode(circleOfRadius: 15)
    var background: SKSpriteNode = SKSpriteNode(imageNamed: "background")

    override func didMove(to view: SKView) {
        background.size = frame.size
        background.position = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height / 2)
        addChild(background)

        let path = CGMutablePath()
        path.addArc(center: CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height / 2),
                    radius: 15,
                    startAngle: 0,
                    endAngle: CGFloat.pi * 2,
                    clockwise: false)
        ball = SKShapeNode(path: path) // Added to center of screen
        ball.lineWidth = 1
        ball.fillColor = .cyan
        ball.strokeColor = .cyan
        ball.glowWidth = 0.5
        addChild(ball)
        print(ball.position)
    }


    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered
        moveNode()
    }

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

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

        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        touched = false
    }

    func moveNode() {
        if touched {
            let speed: CGFloat = 1
            if location.x < ball.position.x {
                let newLocation = ball.position.x - speed
                ball.position = CGPoint(x: newLocation, y: ball.position.y)
            } else {
                let newLocation = ball.position.x + speed
                ball.position = CGPoint(x: newLocation, y: ball.position.y)
            }
        }
    }
}

Upvotes: 1

Views: 79

Answers (1)

Jean-Baptiste Yun&#232;s
Jean-Baptiste Yun&#232;s

Reputation: 36391

You never set the ball position so it is (0,0). The problem is that the ball is at (0,0) but its path represents something at (189,335) in ball coordinates. Change to:

override func didMove(to view: SKView) {
    background.size = frame.size
    background.position = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height / 2)
    addChild(background)

    let path = CGMutablePath()
    // construct a path relative to center of the ball
    path.addArc(center: CGPoint(x: 0, y: 0),
                radius: 15,
                startAngle: 0,
                endAngle: CGFloat.pi * 2,
                clockwise: false)
    ball = SKShapeNode(path: path)
    // locate the ball at the center of the screen
    ball.position = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height / 2)
    ball.lineWidth = 1
    ball.fillColor = .cyan
    ball.strokeColor = .cyan
    ball.glowWidth = 0.5
    addChild(ball)
    print(ball.position)
}

Upvotes: 1

Related Questions