iosswiftsprite-kitskcameranode

Spritekit Camera Node scale but pin the bottom of the scene


I have a camera node that is scaled at 1. When I run the game, I want it to scale it down (i.e. zoom out) but keep the "floor" at the bottom. How would I go about pinning the camera node to the bottom of the scene and effectively zooming "up" (difficult to explain). So the bottom of the scene stays at the bottom but the rest zooms out.

I have had a go with SKConstraints but not having any luck (I'm quite new at SpriteKit)

func setConstraints(with scene: SKScene, and frame: CGRect, to node: SKNode?) {
        let scaledSize = CGSize(width: scene.size.width * xScale, height: scene.size.height * yScale)
        let boardContentRect = frame

        let xInset = min((scaledSize.width / 2), boardContentRect.width / 2)
        let yInset = min((scaledSize.height / 2), boardContentRect.height / 2)
        let insetContentRect = boardContentRect.insetBy(dx: xInset, dy: yInset)

        let xRange = SKRange(lowerLimit: insetContentRect.minX, upperLimit: insetContentRect.maxX)
        let yRange = SKRange(lowerLimit: insetContentRect.minY, upperLimit: insetContentRect.maxY)

        let levelEdgeConstraint = SKConstraint.positionX(xRange, y: yRange)

        if let node = node {
            let zeroRange = SKRange(constantValue: 0.0)
            let positionConstraint = SKConstraint.distance(zeroRange, to: node)
            constraints = [positionConstraint, levelEdgeConstraint]
        } else {
            constraints = [levelEdgeConstraint]
        }


    }

then calling the function with:

gameCamera.setConstraints(with: self, and: scene!.frame, to: nil)

(This was code from a tutorial I was following) The "setConstraints" function is an extension of SKCameraNode

I'm not sure this will give me the correct output, but when I run the code to scale, it just zooms from the middle and shows the surrounding area of the scene .sks file.

gameCamera.run(SKAction.scale(to: 0.2, duration: 100))

This is the code to scale the gameCamera

EDIT: Answer below is nearly what I was looking for, this is my updated answer:

let scaleTo = 0.2
let duration = 100
let scaleTop = SKAction.customAction(withDuration:duration){
                           (node, elapsedTime) in
            let newScale = 1 - ((elapsedTime/duration) * (1-scaleTo))
            let currentScaleY = node.yScale
            let currentHeight = node.scene!.size.height * currentScaleY
            let newHeight =  node.scene!.size.height * newScale
                           let heightDiff = newHeight - currentHeight
                           let yOffset = heightDiff / 2
                            node.setScale(newScale)
                           node.position.y += yOffset
                       }

Solution

  • You cannot use a constraint because your scale size is dynamic.

    Instead you need to move your camera position to give the illusion it is only scaling in 3 directions.

    To do this, I would recommend creating a custom action.

    let scaleTo = 2.0
    let duration = 1.0
    let currentNodeScale = 0.0
    let scaleTop = SKCustomAction(withDuration:duration){
                       (node, elapsedTime) in
                       if elapsedTime == 0 {currentNodeScale = node.scale}
                       let newScale = currentNodeScale - ((elapsedTime/duration) * (currentNodeScale-scaleTo))
                       let currentYScale = node.yScale
                       let currentHeight = node.scene.size.height * currentYScale
                       let newHeight =  node.scene.size.height * newScale
                       let heightDiff = newHeight - currentHeight
                       let yOffset = heightDiff / 2
                       node.scale(to:newScale)
                       node.position.y += yOffset
    
                   }
    

    What this is doing is comparing the new height of your camera with the old height, and moving it 1/2 the distance.

    So if your current height is 1, this means your camera sees [-1/2 to 1/2] on the y axis. If you new scale height is 2, then your camera sees [-1 to 1] on the y axis. We need to move the camera up so that the camera sees [-1/2 to 3/2], meaning we need to add 1/2. So we do 2 - 1, which is 1, then go 1/2 that distance. This makes our yOffset 1/2, which you add to the camera.