ba0708
ba0708

Reputation: 10599

Gradually increasing speed of scrolling background in SpriteKit

I am making a simple game in SpriteKit, and I have a scrolling background. What simply happens is that a few background images are placed adjacent to each other when the game scene is loaded, and then the image is moved horizontally when it scrolls out of the screen. Here is the code for that, from my game scene's didMoveToView method.

// self.gameSpeed is 1.0 and gradually increases during the game

let backgroundTexture = SKTexture(imageNamed: "Background")
var moveBackground = SKAction.moveByX(-self.frame.size.width, y: 0, duration: (20 / self.gameSpeed))
var replaceBackground = SKAction.moveByX(self.frame.size.width, y: 0, duration: 0)
var moveBackgroundForever = SKAction.repeatActionForever(SKAction.sequence([moveBackground, replaceBackground]))

for var i:CGFloat = 0; i < 2; i++ {
    var background = SKSpriteNode(texture: backgroundTexture)
    background.position = CGPoint(x: self.frame.size.width / 2 + self.frame.size.width * i, y: CGRectGetMidY(self.frame))
    background.size = self.frame.size
    background.zPosition = -100
    background.runAction(moveBackgroundForever)

    self.addChild(background)
}

Now I want to increase the speed of the scrolling background at certain points of the game. You can see that the duration of the background's horizontal scroll is set to (20 / self.gameSpeed). Obviously this does not work, because this code is only run once, and therefore the movement speed is never updated to account for a new value of the self.gameSpeed variable.

So, my question is simply: how do I increase the speed (reduce the duration) of my background images' movements according to the self.gameSpeed variable?

Thanks!

Upvotes: 4

Views: 1171

Answers (2)

ABakerSmith
ABakerSmith

Reputation: 22939

You could use the gameSpeed variable to set the velocity of the background. For this to work, firstly, you need to have a reference to your two background pieces (or more if you so wanted):

class GameScene: SKScene {
    lazy var backgroundPieces: [SKSpriteNode] = [SKSpriteNode(imageNamed: "Background"), 
                                                 SKSpriteNode(imageNamed: "Background")]

    // ... 
}

Now you need your gameSpeed variable:

var gameSpeed: CGFloat = 0.0 {
    // Using a property observer means you can easily update the speed of the 
    // background just by setting gameSpeed.
    didSet {
        for background in backgroundPieces {
            // Minus, because the background is moving from left to right.
            background.physicsBody!.velocity.dx = -gameSpeed
        }
    }
}

Then position each piece correctly in didMoveToView. Also, for this method to work each background piece needs a physics body so you can easily change its velocity.

override func didMoveToView(view: SKView) {
    for (index, background) in enumerate(backgroundPieces) {
        // Setup the position, zPosition, size, etc...

        background.physicsBody = SKPhysicsBody(rectangleOfSize: background.size)
        background.physicsBody!.affectedByGravity = false
        background.physicsBody!.linearDamping = 0
        background.physicsBody!.friction = 0

        self.addChild(background)
    }

    // If you wanted to give the background and initial speed,
    // here's the place to do it.
    gameSpeed = 1.0
}

You could update gameSpeed in update for example with gameSpeed += 0.5.

Finally, in update you need to check if a background piece has gone offscreen (to the left). If it has it needs to be moved to the end of the chain of background pieces:

override func update(currentTime: CFTimeInterval) {
    for background in backgroundPieces {
        if background.frame.maxX <= 0 {
            let maxX = maxElement(backgroundPieces.map { $0.frame.maxX })

            // I'm assuming the anchor of the background is (0.5, 0.5)
            background.position.x = maxX + background.size.width / 2
        }
    }
}

Upvotes: 3

Wraithseeker
Wraithseeker

Reputation: 1904

You could make use of something like this

SKAction.waitforDuration(a certain amount of period to check for the updated values) 

SKAction.repeatActionForever(the action above)
runAction(your action)
{ // this is the completion block, do whatever you want here, check the values and adjust them accordly
}

Upvotes: 0

Related Questions