Pinch Gesture Not Working with SKCameraNode

679 views Asked by At

I'm working with Swift 4 using SpriteKit with an SKTileMapNode and an SKCameraNode. I want to be able to pan/pinch/zoom on the tile map node using the camera. I've got panning working well but I'm running into some issues with pinch/zooming.

  1. While I can get the pinch to work. It resets the size every time another pinch happens. So for example, I'll make it smaller then go to pinch again and as soon as I touch the screen, it jumps up in size. It does let me pinch again to zoom in/out but not based on the size I made it in the prior pinch. I think I may need to store the resize scale and use that but not sure how.

  2. My pinch zooming is reversed. When I pinch to zoom in, it zooms out and vice versa.

  3. When I hit the min/max scale limits, it stops from going further but stutters when at the limits.

Here is my function to process the pinch:

@objc func handlePinch(pinchGesture: UIPinchGestureRecognizer) {

      if pinchGesture.state == .began || pinchGesture.state == .changed {

          let currentScale: CGFloat = (camera?.xScale)!
          let minScale: CGFloat = 0.5
          let maxScale: CGFloat = 2.0
          let zoomSpeed: CGFloat = 0.5
          var deltaScale = pinchGesture.scale

          deltaScale = ((deltaScale - 1) * zoomSpeed) + 1
          deltaScale = min(deltaScale, maxScale / currentScale)
          deltaScale = max(deltaScale, minScale / currentScale)

          camera?.xScale = deltaScale
          camera?.yScale = deltaScale
      }
}

Let me know if you have any suggestions as I've looked around a bunch and I can't find examples where people are using an SKCameraNode. The examples I find either I can't get to work trying to convert from a view to a camera or they don't give a pinch example. Any help would be greatly appreciated!

1

There are 1 answers

0
Aaron Brager On

While I can get the pinch to work. It resets the size every time another pinch happens. So for example, I'll make it smaller then go to pinch again and as soon as I touch the screen, it jumps up in size. It does let me pinch again to zoom in/out but not based on the size I made it in the prior pinch. I think I may need to store the resize scale and use that but not sure how.

This is because a gesture recognizer retains its properties between recognitions. You may wish to reset scale when the gesture ends. For example you could start your method with something like:

guard pinchGesture.state != .ended else {
    pinchGesture.scale = 0
    return
}

My pinch zooming is reversed. When I pinch to zoom in, it zooms out and vice versa.

From the SKCameraNode docs:

In this way, a camera’s position, scale, and rotation always have the opposite effect on how the scene is rendered. For example, if the camera is moved 10 pixels to the right, then the scene is rendered as if everything else moved 10 pixels to the left. And similarly, if a camera node has an xScale and yScale of 2.0, then scene is rendered as if every distance was half its normal size, effectively increasing the visible area of the camera’s viewport.

I'm not sure exactly what effect you're looking for, but you may want to try inverting the pinch gesture recognizer's scale by dividing one by it, e.g.:

var deltaScale = pinchGesture.scale / 1
camera?.xScale = deltaScale
camera?.yScale = deltaScale

When I hit the min/max scale limits, it stops from going further but stutters when at the limits.

Not sure without seeing specific values, but it's possible this is caused by rounding issues. You might want to avoid touching the SKCameraNode if you're outside the range. You could try an approach like this:

var deltaScale = pinchGesture.scale / 1

guard deltaScale > minScale && deltaScale < maxScale else { return } 

camera?.xScale = deltaScale
camera?.yScale = deltaScale