sasklacz
sasklacz

Reputation: 3638

Correctly position the camera when panning

I'm having a hard time setting boundaries and positioning camera properly inside my view after panning. So here's my scenario.

I have a node that is bigger than the screen and I want to let user pan around to see the full map. My node is 1000 by 1400 when the view is 640 by 1136. Sprites inside the map node have the default anchor point. Then I've added a camera to the map node and set it's position to (0.5, 0.5).

enter image description here

Now I'm wondering if I should be changing the position of the camera or the map node when the user pans the screen ? The first approach seems to be problematic, since I can't simply add translation to the camera position because position is defined as (0.5, 0.5) and translation values are way bigger than that. So I tried multiplying/dividing it by the screen size but that doesn't seem to work. Is the second approach better ?

var map = Map(size: CGSize(width: 1000, height: 1400))

override func didMove(to view: SKView) {
    (...)
    let pan = UIPanGestureRecognizer(target: self, action: #selector(panned(sender:)))
    view.addGestureRecognizer(pan)

    self.anchorPoint = CGPoint.zero
    self.cam = SKCameraNode()
    self.cam.name = "camera"

    self.camera = cam
    self.addChild(map)
    self.map.addChild(self.cam!)

    cam.position = CGPoint(x: 0.5, y: 0.5)
}

var previousTranslateX:CGFloat = 0.0

func panned (sender:UIPanGestureRecognizer) {
    let currentTranslateX = sender.translation(in: view!).x

    //calculate translation since last measurement
    let translateX = currentTranslateX - previousTranslateX

    let xMargin = (map.nodeSize.width - self.frame.width)/2

    var newCamPosition = CGPoint(x: cam.position.x, y: cam.position.y)
    let newPositionX = cam.position.x*self.frame.width + translateX

    // since the camera x is 320, our limits are 140 and 460 ?
    if newPositionX > self.frame.width/2 - xMargin && newPositionX < self.frame.width - xMargin {
        newCamPosition.x = newPositionX/self.frame.width
    }

    centerCameraOnPoint(point: newCamPosition)

    //(re-)set previous measurement
    if sender.state == .ended {
        previousTranslateX = 0
    } else {
        previousTranslateX = currentTranslateX
    }
}

func centerCameraOnPoint(point: CGPoint) {
    if cam != nil {
        cam.position = point
    }
}

Upvotes: 5

Views: 791

Answers (1)

Confused
Confused

Reputation: 6288

Your camera is actually at a pixel point 0.5 points to the right of the centre, and 0.5 points up from the centre. At (0, 0) your camera is dead centre of the screen.

I think the mistake you've made is a conceptual one, thinking that anchor point of the scene (0.5, 0.5) is the same as the centre coordinates of the scene.

If you're working in pixels, which it seems you are, then a camera position of (500, 700) will be at the top right of your map, ( -500, -700 ) will be at the bottom left.

This assumes you're using the midpoint anchor that comes default with the Xcode SpriteKit template.

Which means the answer to your question is: Literally move the camera as you please, around your map, since you'll now be confident in the knowledge it's pixel literal.

With one caveat...

a lot of games use constraints to stop the camera somewhat before it gets to the edge of a map so that the map isn't half off and half on the screen. In this way the map's edge is showing, but the furthest the camera travels is only enough to reveal that edge of the map. This becomes a constraints based effort when you have a player/character that can walk/move to the edge, but the camera doesn't go all the way out there.

Upvotes: 4

Related Questions