1

I have ball sprite that i want to be able to flick towards other sprites. Right now, I have the function TouchesMoved below, but it moves my sprite towards any touch movement on the screen, when I want my user to first touch the sprite and drag their finger towards the target, causing the sprite to move. This is the dysfunctional function.. Any help would be appreciated!

EDIT: I wanted the ball velocity to remain constant no matter the flick length.. not addressed by other answers.

    override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {

    if firstTimerStarted == false {
        let touch = touches.first as! UITouch
        let touchLocation = touch.locationInNode(self)
        sceneTouched(touchLocation)

    }
Daniel Mihaila
  • 585
  • 1
  • 6
  • 13

1 Answers1

2

This should work, I just dug it out from an old project.

CGFloat dt is for changing the speed/power of the movement.

var touching = false

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {

    let touch = touches.first as! UITouch
    let location = touch.locationInNode(self)
    if sprite.frame.contains(location) {
        touchPoint = location
        touching = true
    }
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {

    let touch = touches.first as! UITouch
    let location = touch.locationInNode(self)
    touchPoint = location
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
    touching = false
}
override func update(currentTime: CFTimeInterval) {
    if touching {
        if touchPoint != sprite.position
        {
            let dt:CGFloat = 0.15
            let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
            let vel = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
            sprite.physicsBody!.velocity = vel
        }
    }
}

EDIT: The reason it gets stronger the farther the distance, is because the vector IS the distance between the the sprite and the touch point. Try popping this in as the update function. It should work...

override func update(currentTime: CFTimeInterval) {
    if touching {
        if touchPoint != sprite.position
        {
            let pointA = touchPoint
            let pointB = sprite.position
            let pointC = CGPointMake(sprite.position.x + 2, sprite.position.y)
            let angle_ab = atan2(pointA.y - pointB.y, pointA.x - pointB.x)
            let angle_cb = atan2(pointC.y - pointB.y, pointC.x - pointB.x)
            let angle_abc = angle_ab - angle_cb
            let vectorx = cos(angle_abc)
            let vectory = sin(angle_abc)
            let dt:CGFloat = 15
            let vel = CGVector(dx: vectorx * dt, dy: vectory * dt)
            sprite.physicsBody!.velocity = vel
        }
    }
}

With the touchPoint (pointA), and the sprite's position (pointB) we can create an angle.

atan2, is a very famous function from C, it creates the angle between two points. BUT, it's 0 degrees is in a different location than usual.

So, we need our own 0 degrees marker, I use the mid-right of the point as my marker. It's the common 0 degree placement:

http://www.cs.ucsb.edu/~pconrad/images/math/unitCircleWithDegrees.png

Since it's to the right of the sprite's position, we create a point just to the right of the sprite (pointC).

We now use atan2 to find the angle.

To create a vector from an angle, we just use cos and sin for the x and y values.

Jake Crastly
  • 462
  • 3
  • 9