Search code examples
swiftbackgroundscene

Swift Game Scene change background with time or score?


I have a background image in my application which moves from top to bottom and repeats. I want a different images to appear on to the screen after x amount of time.

Would this do?

When would be best to remove the initial bg to avoid too many layers?

    override func didMove(to view: SKView) {

    let bgTexture = SKTexture(imageNamed: "bg1.png")
    let moveBGanimation = SKAction.move(by: CGVector(dx: 0, dy: -bgTexture.size().height), duration: 4)
    let shiftBGAnimation = SKAction.move(by: CGVector(dx: 0, dy: bgTexture.size().height), duration: 0)
    let moveBGForever = SKAction.repeatForever(SKAction.sequence([moveBGanimation, shiftBGAnimation]))

    var i: CGFloat = 0

    while i < 3 {

        bg = SKSpriteNode(texture: bgTexture)
        bg.position = CGPoint(x: self.frame.midX, y: bgTexture.size().height * i)
        bg.size.width = self.frame.width
        bg.zPosition = -2

        bg.run(moveBGForever)
        self.addChild(bg)

        i += 1


    }

    bg2Timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(self.moveBG2), userInfo: nil, repeats: false)

}

func moveBG2() {

    let bg2Texture = SKTexture(imageNamed: "bg2.png")
    let moveBG2animation = SKAction.move(by: CGVector(dx: 0, dy: -bg2Texture.size().height * 2), duration: 8)
    let shiftBG2Animation = SKAction.move(by: CGVector(dx: 0, dy: bg2Texture.size().height), duration: 0)
    let moveBG2Forever = SKAction.repeatForever(SKAction.sequence([moveBG2animation, shiftBG2Animation]))

    var j: CGFloat = 0

    while j < 3 {

        bg2 = SKSpriteNode(texture: bg2Texture)
        bg2.position = CGPoint(x: self.frame.midX, y: bg2Texture.size().height + bg2Texture.size().height * j)
        bg2.size.width = self.frame.width
        bg2.zPosition = -1.5


        bg2.run(moveBG2Forever)
        self.addChild(bg2)

        j += 1


    }



}

Solution

  • Here is an idea that I came up with.

    Refactor this piece of code:

    let bgTexture = SKTexture(imageNamed: "bg.png")
        let moveBGanimation = SKAction.move(by: CGVector(dx: 0, dy: -bgTexture.size().height), duration: 4)
        let shiftBGAnimation = SKAction.move(by: CGVector(dx: 0, dy: bgTexture.size().height), duration: 0)
        let moveBGForever = SKAction.repeatForever(SKAction.sequence([moveBGanimation, shiftBGAnimation]))
    

    to a method:

    func runBgActions(bgTextureName: String) {
        let bgTexture = SKTexture(imageNamed: bgTextureName)
        bg.texture = bgTexture
            let moveBGanimation = SKAction.move(by: CGVector(dx: 0, dy: -bgTexture.size().height), duration: 4)
            let shiftBGAnimation = SKAction.move(by: CGVector(dx: 0, dy: bgTexture.size().height), duration: 0)
            let moveBGForever = SKAction.repeatForever(SKAction.sequence([moveBGanimation, shiftBGAnimation]))
        bg.removeAllActions()
        bg.run(moveBGForever)
    }
    

    Then, create another action and run it on a node that's not bg, maybe the scene itself.

    let bg1Action = SKAction.run { runBgActions(bgTextureName: "bg1") }
    let bg2Action = SKAction.run { runBgActions(bgTextureName: "bg2") }
    let bg3Action = SKAction.run { runBgActions(bgTextureName: "bg3") }
    let waitAction = SKAction.wait(forDuration: 10)
    let sequence = SKAction.sequence([bg1Action, waitAction, bg2Action, waitAction, bg3Action, waitAction])
    let repeatForeverAction = SKAction.repeatForever(sequence)
    self.run(repeatForeverAction) // assuming self is the scene here
    

    An alternative approach would be to use SKAction.group to execute the wait and shifting background actions at the same time, but I find that quite counter-intuitive to implement.

    After seeing your code, this is what I have been able to come up with:

    var bg = SKSpriteNode()
    
    func runBgActions(bgTextureName: String) {
        let bgTexture = SKTexture(imageNamed: bgTextureName)
        bg.texture = bgTexture
        bg.position = CGPoint(x: self.frame.minX, y: self.frame.minY)
        let moveBGanimation = SKAction.move(by: CGVector(dx: 0, dy: -(bgTexture.size().height - self.frame.height)), duration: 4)
        let shiftBGAnimation = SKAction.move(by: CGVector(dx: 0, dy: bgTexture.size().height - self.frame.height), duration: 0)
        let moveBGForever = SKAction.repeatForever(SKAction.sequence([moveBGanimation, shiftBGAnimation]))
        bg.removeAllActions()
        bg.run(moveBGForever)
    }
    
    override func didMove(to view: SKView) {
        var i: CGFloat = 0
    
        bg = SKSpriteNode(imageNamed: "bg1") // replace this with your first background's texture name
        bg.position = CGPoint(x: self.frame.minX, y: self.frame.minY)
        bg.anchorPoint = CGPoint(x: 0, y: 0)
        bg.size.width = self.frame.width
        bg.zPosition = -2
        self.addChild(bg)
    
        i += 1
        let bg1Action = SKAction.run { self.runBgActions(bgTextureName: "bg1") }
        let bg2Action = SKAction.run { self.runBgActions(bgTextureName: "bg2") }
        let bg3Action = SKAction.run { self.runBgActions(bgTextureName: "bg3") }
        let waitAction = SKAction.wait(forDuration: 10)
        let sequence = SKAction.sequence([bg1Action, waitAction, bg2Action, waitAction, bg3Action, waitAction])
        let repeatForeverAction = SKAction.repeatForever(sequence)
        self.run(repeatForeverAction)
    }