Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpriteKit - SKCameraNode Parallax effect?

I've been experimenting with SKCameraNode, but I can't find anything about creating a parallax effect with it.

Let's say I add to the code above and I add a behindNode below my baseNode. Then I animate my camera.

let behindNode = SKNode()
addChild(behindNode)

let blueSquare = SKSpriteNode(color: SKColor.blueColor(), size: CGSize(width: 80, height: 80))
blueSquare.position = CGPoint(x: size.width/2+40, y: size.height/2+40)
behindNode.addChild(blueSquare)

let baseNode = SKNode()
addChild(baseNode)

let redSquare = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 80, height: 80))
redSquare.position = CGPoint(x: size.width/2, y: size.height/2)
baseNode.addChild(redSquare)


let cameraNode = SKCameraNode()
camera = cameraNode
addChild(camera!)
camera!.position = redSquare.position

cameraNode.runAction(SKAction.sequence([
    SKAction.waitForDuration(1),
    SKAction.moveBy(CGVector(dx: 100, dy: 100), duration: 3),
    SKAction.moveBy(CGVector(dx: -100, dy: 100), duration: 1),
    SKAction.moveBy(CGVector(dx: 100, dy: -100), duration: 1)
]))

enter image description here

I need the blue square to move at a slower rate relative to the red square when the camera moves.. I would expect the cameranode to have a relative positions dictionary or something, but it doesn't..

like image 894
hamobi Avatar asked Jan 31 '26 01:01

hamobi


1 Answers

I created a solution that does not deal with seconds or frames.

You can create a subclass of SKCameraNode and use Swift's didSet() method that gets called after a class variable was changed. In our case we want to listen to the changes of the camera node's position variable.

class CameraNodeParallax:SKCameraNode{

override var position : CGPoint {
    didSet {  
       // Move our backgrounds
    }
}

We further want to create one array that contains all our parallax background nodes and one that contains the corresponding moving speed in relation to the camera's moving speed.

var backgroundNodes:[SKNode] = []
var backgroundNodesSpeedFactor:[CGVector] = [] // in relation to camera nodes speed

func addParallaxBackgroundNode(background:SKNode, vector:CGVector) {
    backgroundNodes.append(background)
    backgroundNodesSpeedFactor.append(vector)
}

A init() that fills our new variables might be useful as well

init(position:CGPoint) {
  super.init()
  self.position = position
}

Now we can fill our didSet() listener:

// Move our backgrounds
var i = 0
for node in backgroundNodes {

    let positionChangeX = position.x-oldValue.x
    let positionChangeY = position.y-oldValue.y
    let changeX = positionChangeX*backgroundNodesSpeedFactor[i].dx
    let changeY = positionChangeY*backgroundNodesSpeedFactor[i].dy
    node.position = CGPointMake(node.position.x+changeX,node.position.y+changeY)

    i += 1
}

The final code looks like this:

class CameraNodeParallax:SKCameraNode{

    var backgroundNodes:[SKNode] = []
    var backgroundNodesSpeedFactor:[CGVector] = [] // in relation to camera nodes speed

    init(position:CGPoint) {
        super.init()
        self.position = position
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override var position : CGPoint {
        didSet {

            // Move your parallax backgrounds
                var i = 0
                for node in backgroundNodes {

                    let positionChangeX = position.x-oldValue.x
                    let positionChangeY = position.y-oldValue.y
                    let changeX = positionChangeX*backgroundNodesSpeedFactor[i].dx
                    let changeY = positionChangeY*backgroundNodesSpeedFactor[i].dy
                    node.position = CGPointMake(node.position.x+changeX,node.position.y+changeY)

                    i += 1
                }
        }
    }

    func addParallaxBackgroundNode(background:SKNode, vector:CGVector) {
        backgroundNodes.append(background)
        backgroundNodesSpeedFactor.append(vector)
    }
}

I created an alternative implementation that does not inherit from SKCameraNode here https://github.com/gitmalong/lovelySpriteKitHelpers/blob/master/ParallaxBackgroundMover.swift

like image 56
bamboofighter Avatar answered Feb 02 '26 16:02

bamboofighter



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!