2

I have the following code at the moment. Even though the code build is successful, i cannot seem to get it to work. I am trying to make it so when you flick the object, it moves at the velocity of your begin and end touch.

import SpriteKit
class GameScene: SKScene {
    var sprite: SKSpriteNode!
    var touchPoint: CGPoint = CGPoint()
    var touching: Bool = false
    override func didMoveToView(view: SKView) {
        self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
        sprite = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 50, height: 50))
        sprite.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.size)
        sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
        self.addChild(sprite)
    }

    //for touch: AnyObject in touches {
    //let location = touch.locationInNode(self)
    //let touchedNode = self.nodeAtPoint(location)

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

        let location = touch.locationInNode(self)
        if sprite.frame.contains(location) {
            touchPoint = location
            touching = true
        }
    }
    func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
        for touch: AnyObject in touches {
        let location = touch.locationInNode(self)
        touchPoint = location
    }
    func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
        touching = false
    }
    func update(currentTime: CFTimeInterval) {
        if touching {
            let dt:CGFloat = 1.0/60.0
            let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
            let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
            sprite.physicsBody!.velocity = velocity
        }
    }
}}}
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
James
  • 31
  • 2
  • Not 100% sure this will help but I think you want to only apply the velocity after you are done flicking. Because you are applying every update you are applying a very small velocity. You may want to try changing the position of the sprite in touchesMoved and then apply the velocity in touches ended based on distance from start and end point. You could also base it on the start time of the flick and the end time of the flick. Also might help if you explain the result you do get other than it builds :) – Skyler Lauren May 22 '15 at 12:07
  • See my answer here! http://stackoverflow.com/a/28259980/2158465 – Epic Byte May 23 '15 at 02:39
  • possible duplicate of [how to throw SKSpriteNode?](http://stackoverflow.com/questions/28245653/how-to-throw-skspritenode) – Epic Byte May 23 '15 at 02:39

3 Answers3

2

You accidentally placed touchesMoved, touchesEnded and update inside touchesBegan. Besides that your code works. A hint that there were problems was the fact you didn't need to prefix touchesMoved, touchesEnded or update with override.

In the future, I would recommend using breakpoints and print statements to check the methods you expect to execute, are in fact running. Doing that you'd see that your versions of touchesMoved, touchesEnded and update weren't being called.

Anyway, here's it corrected it and now it works perfectly:

import SpriteKit
class GameScene: SKScene {
    var sprite: SKSpriteNode!
    var touchPoint: CGPoint = CGPoint()
    var touching: Bool = false
    override func didMoveToView(view: SKView) {
        self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
        sprite = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 50, height: 50))
        sprite.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.size)
        sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
        self.addChild(sprite)
    }

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

            let location = touch.locationInNode(self)
            if sprite.frame.contains(location) {
                touchPoint = location
                touching = true
            }
        }
    }

    override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
        for touch: AnyObject in touches {
            let location = touch.locationInNode(self)
            touchPoint = location
        }
    }

    override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
        touching = false
    }

    override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
        touching = false
    }

    override func update(currentTime: NSTimeInterval) {
        if touching {
            let dt:CGFloat = 1.0/60.0
            let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
            let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
            sprite.physicsBody!.velocity = velocity
        }
    }
}
ABakerSmith
  • 22,759
  • 9
  • 68
  • 78
  • Thanks heaps! It works now :) Quick question, how would I make it so the sprite will not move until you flick it? So you cannot drag it around and so it has a original location? – James May 22 '15 at 12:29
  • I would recommend looking at [this](http://stackoverflow.com/questions/28552408/how-do-i-implement-velocityinview-for-a-custom-gesture-recognizer/29479092#29479092) for information on getting the velocity of a gesture recogniser (you've got all the same methods there as in your `SKScene`). Then you could just give the sprite velocity in `touchesEnded`. Also, if the answer solved your question would you consider marking it as correct? :) – ABakerSmith May 22 '15 at 12:41
  • Happy to help :) Good luck with your project! – ABakerSmith May 22 '15 at 13:32
1

ABakerSmith's solutions updated for Swift 4:

import SpriteKit
class GameScene: SKScene {
    var sprite: SKSpriteNode!
    var touchPoint: CGPoint = CGPoint()
    var touching: Bool = false
    override func didMove(to view: SKView) {
        self.physicsBody = SKPhysicsBody.init(edgeLoopFrom: self.frame)
        sprite = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))
        sprite.physicsBody = SKPhysicsBody.init(rectangleOf: sprite.size)
        sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
        self.addChild(sprite)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first?.location(in: self) {
            if sprite.frame.contains(touch) {
                touchPoint = touch
                touching = true
            }
        }
    }

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

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

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

    override func update(_ currentTime: TimeInterval) {
        if touching {
            let dt:CGFloat = 1.0/60.0
            let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
            let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
            sprite.physicsBody!.velocity = velocity
        }
    }
}
peacetype
  • 1,928
  • 3
  • 29
  • 49
0

Solution updated to not have the touch/drag snap to the middle of the sprite. If you're dragging/throwing an object you're going to want that throw to come from where the user touched the object and not snap to the middle of the object. This will make it look a lot smoother

import SpriteKit
class GameScene: SKScene {
    var sprite: SKSpriteNode!
    var touchPoint: CGPoint = CGPoint()
    var touching: Bool = false
    var xDif = CGFloat()
    var yDif = CGFloat()

    override func didMove(to view: SKView) {
        self.physicsBody = SKPhysicsBody.init(edgeLoopFrom: self.frame)
        sprite = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))
        sprite.physicsBody = SKPhysicsBody.init(rectangleOf: sprite.size)
        sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
        self.addChild(sprite)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first?.location(in: self) {
            xDif = sprite.position.x - touch.x
            yDif = sprite.position.y - touch.y

            if sprite.frame.contains(touch) {
                touchPoint = touch
                touching = true
            }
        }
    }

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

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

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

    override func update(_ currentTime: TimeInterval) {
        if touching {
            let dt:CGFloat = 1.0/60.0
            let distance = CGVector(dx: touchPoint.x-sprite.position.x + xDif, dy: touchPoint.y-sprite.position.y + yDif)
            let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
            sprite.physicsBody!.velocity = velocity
        }
    }
}
Colton
  • 1