Question on moving around in a scene with touch

Hi guys,


I've been struggling with this for a few days now. I have a scene in my game (not the main scene) where I want to display a very large map. I'm trying to get that scene to scroll in all directions based on touch and be able to interact with landmarks I place. I'm not having much luck and am looking for some advice. The closest I got was using a UIPanGestureRecognizer which I had to add as a UIView instead of an SKNode. While I was able to scroll around an image (it was actually the image that was scrolling). I didn't appear to have a way to add objects in such a way that I could interact with them.


I also tried an example of a camera that should have followed my swipes with a finger but that didn't work either. I'm stuck and I'd love to hear your suggestions!


- Thanks

Accepted Reply

Here's some Swift 3 code to help out. Declare the pan gesture variable and a CGPoint variable ...


let panRec = UIPanGestureRecognizer()
var previousPan:CGPoint = CGPoint.zero


In any function (probably didMove), add the target function, set minimum touches and add it to the view.


panRec.addTarget(self, action: #selector(Page.panned(_:)))
panRec.minimumNumberOfTouches = 1
self.view!.addGestureRecognizer(panRec)


Once that's done, the panned function will run whenever panning occurs. So to summarize what's going on, we only want to move a particular node based on the difference between the current touch location and where the touch was the last frame (thats what's stored in the previousPan CGPoint). So the difference is a very small amount, but obviously we want small amounts or otherwise the node to move goes shooting off from its current location.




  func panned(_ sender:UIPanGestureRecognizer) {


        var touchLocation:CGPoint = sender.location(in: self.view!)

        touchLocation = self.convertPoint(fromView: touchLocation)


        if (sender.state == .changed) {

           //panning is occuring
            if ( previousPan != CGPoint.zero) {
                 //if previousPan has been set, this can run
     
                panXDiff = touchLocation.x - previousPan.x
                panYDiff = touchLocation.y - previousPan.y

               //replace node below with the name of the sprite you want to move

                node.position = CGPoint( x: node.position.x - panXDiff, y: node.position.y + panYDiff )

             }
          //save the location to previousPan to be used the next frame of panning
          previousPan = touchLocation
          }
         else  if (sender.state == .ended ) {

          //panning ended, so reset previousPan to 0,0
               previousPan = CGPoint.zero

          }

Replies

Well I think you need to remove the UIView and switch back to using an SKSpriteNode. You'll cause more problems down the road by mixing in a UIView unnecessarily into your sprite kit scene. You should have no problem panning an SKSpriteNode.

Here's some Swift 3 code to help out. Declare the pan gesture variable and a CGPoint variable ...


let panRec = UIPanGestureRecognizer()
var previousPan:CGPoint = CGPoint.zero


In any function (probably didMove), add the target function, set minimum touches and add it to the view.


panRec.addTarget(self, action: #selector(Page.panned(_:)))
panRec.minimumNumberOfTouches = 1
self.view!.addGestureRecognizer(panRec)


Once that's done, the panned function will run whenever panning occurs. So to summarize what's going on, we only want to move a particular node based on the difference between the current touch location and where the touch was the last frame (thats what's stored in the previousPan CGPoint). So the difference is a very small amount, but obviously we want small amounts or otherwise the node to move goes shooting off from its current location.




  func panned(_ sender:UIPanGestureRecognizer) {


        var touchLocation:CGPoint = sender.location(in: self.view!)

        touchLocation = self.convertPoint(fromView: touchLocation)


        if (sender.state == .changed) {

           //panning is occuring
            if ( previousPan != CGPoint.zero) {
                 //if previousPan has been set, this can run
     
                panXDiff = touchLocation.x - previousPan.x
                panYDiff = touchLocation.y - previousPan.y

               //replace node below with the name of the sprite you want to move

                node.position = CGPoint( x: node.position.x - panXDiff, y: node.position.y + panYDiff )

             }
          //save the location to previousPan to be used the next frame of panning
          previousPan = touchLocation
          }
         else  if (sender.state == .ended ) {

          //panning ended, so reset previousPan to 0,0
               previousPan = CGPoint.zero

          }

Thank you CartoonSmart, with some minor edits I was able to get the recognizer working by following your example.

I have been trying to accomplish the same but with translation


@objc func panGestureHandler(_ recognizer: UIPanGestureRecognizer) {
    if recognizer.state == .began {
        print("Touchdown")


        var touchLocation = recognizer.location(in: recognizer.view)
        touchLocation = self.convertPoint(fromView: touchLocation)
        if (self.atPoint(touchLocation) is SKSpriteNode){
            selectedNode = self.atPoint(touchLocation) as! SKSpriteNode
        } else {
            recognizer.state = .failed
        }




    } else if recognizer.state == .changed {


        var translation = recognizer.translation(in: recognizer.view!)
        translation = CGPoint(x: translation.x, y: -translation.y) //-y for spritekit


        selectedNode.position = CGPoint(x: pos.x + translation.x, y:  pos.y + translation.y)
        pos = selectedNode.position //pos initialized to the SKSpritNode position as CGPoint


    } else if recognizer.state == .ended {


    }


Please Help