0
votes

I'm making a game with swift and spritekit and I have a function where I have multiple sprites falling from the top of the screen. I also made it so I can be able to detect a touch on the sprite using nodeAtPoint, and made it possible to flick the sprites. My problem is that due to nodeAtPoint dragging the deepest node in the tree, when i click and drag on a sprite, the newest sprite in the scene gets pulled toward my touch instead of the one i originally touched. If anyone has some suggestions on how to only affect the node I touched I'd really appreciate it.

    class GameScene: SKScene {

    var ball = SKSpriteNode(imagedNamed: "blueBlue")

    var touchedNode: SKNode? = SKNode()

     override func didMoveToView(view: SKView) {

       var create = SKAction.runBlock({() in self.createTargets()})
            var wait = SKAction.waitForDuration(2)
            var waitAndCreateForever = SKAction.repeatActionForever(SKAction.sequence([create, wait]))
            self.runAction(waitAndCreateForever)
    }


        func createTargets() {
             ball = SKSpriteNode(imageNamed: "blueBlue")
             let randomx = Int(arc4random_uniform(170) + 290)
             ball.zPosition = 0
            ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width / 11)

            ball.physicsBody?.dynamic = true
            ball.size = CGSize(width: ball.size.width / 1.5, height: ball.size.height / 1.5)
            let random = Int(arc4random_uniform(35))

            let textures = [texture1, texture2, texture3, texture4, texture5, texture6, texture7, texture8, texture9, texture10, texture11, texture12, texture13, texture14, texture15, texture16, texture17, texture18, texture19, texture20, texture21, texture22, texture23, texture24, texture25, texture1, texture7, texture18, texture24, texture25, texture1, texture7, texture18, texture24, texture25]

            ball.texture = textures[random] 
            ball.position = CGPoint(x: randomx, y: 1400) 
            addChild(ball)
    }
        override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
            let touch = touches.first as! UITouch
            let touchLocation = touch.locationInNode(self)
           touchedNode = self.nodeAtPoint(touchLocation)
            if touchedNode.frame.contains(touchLocation) {
            touching = true
            touchPoint = touchLocation
            }
       }

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

        }
     override func update(currentTime: NSTimeInterval) {

            if touching {

                if touchPoint != touchedNode.position {

                    let dt: CGFloat = 0.1

                    let distance = CGVector(dx: touchPoint.x - touchedNode.position.x, dy: touchPoint.y - touchedNode.position.y)

                    let vel = CGVector(dx: distance.dx / dt, dy: distance.dy / dt)

                    if touchedNode.parent != nil {

                    touchedNode.physicsBody?.velocity = vel

                }    
             }
            }  
        }
    }
1
Not sure if this will help you but see here: stackoverflow.com/a/28259980/2158465 - Epic Byte
@EpicByte looks like the OP's code is based on your post. I found it interesting that the code sets the velocity to move the physics body instead of using a force or impulse - 0x141E
yup I got the code from someone else who probably got it from your post. - Daniel Mihaila
@0x141E I always choose to set the velocity directly instead of indirectly through the applyImpulse/force methods, especially if i'm performing a custom real-time calculation such as moving to a point, simulating buoyancy, etc; It's also slightly faster and gives me complete control over the calculation. Only time I apply impulse and forces is if i'm not doing the calculations myself. For example maybe I want to apply an impulse at a point, or maybe I want to account for the mass of the physics body etc. In these cases I simply let the physics engine determine the velocity for me. - Epic Byte
@DanielMihaila Is your issue resolved or do you still have a problem? - Epic Byte

1 Answers

0
votes

I suggest you make the following changes to the code:

  1. Add a check to see if a sprite is already being moved (if yes, do nothing)
  2. Turn off the affectedByGravity property for the sprite being moved
  3. Reset touchedNode and touching variables when the touch ends

Here's an implementation with the above changes...

Replace touchesBegan and touchesMoved with the following

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    let touch = touches.first as! UITouch
    let touchLocation = touch.locationInNode(self)
    if (!touching) {
        let node = self.nodeAtPoint(touchLocation)
        if node is SKSpriteNode {
            touchedNode = node
            touching = true
            touchPoint = touchLocation
            touchedNode!.physicsBody?.affectedByGravity = false
        }
    }
}

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

And add this method

override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
    if (touchedNode != nil) {
        touchedNode!.physicsBody!.affectedByGravity = true
    }
    touchedNode = nil
    touching = false
}