Categories
Scrolling SpriteKit SWIFT

Quick Tip: Endless scrolling with SpriteKit and SWIFT (Part 1 of 2)

Endless scrolling with background tiles

 

Welcome to my tutorial series about scrolling:
  • Part 1: Endless scrolling with background tiles
  • Part 2: Natural endless scrolling with easing
This video gives an impression what I’ll show today:
 
 
 

1. About the algorithm and the background tiles

 

Creating the image tiles for the scrolling parts of the background:

First we need a background image:

SpriteKit Scrolling Tutorial 1
 
Let’s mirror this image and add the new one at the right side:

 

SpriteKit Scrolling Tutorial 2
 
 

Copy the original image and append it at the right side. In our app we will have three sprite nodes, one for each image tile:

SpriteKit Scrolling Tutorial 3

Scrolling will start at the left side:

SpriteKit Scrolling Tutorial 4

Let’s add a static background image:

SpriteKit Scrolling Tutorial 5
 
To scroll right, move the background tiles in the left direction:
 
SpriteKit Scrolling Tutorial 6
 
If the end at the right side is reached:
SpriteKit Scrolling Tutorial 7

Move the background tiles back to the start position:

SpriteKit Scrolling Tutorial 8

The SpriteKits object hierarchy will be created this way:

  • scene (SKScene)
    • backgroundNode (SKSpriteNode)
    • worldNode (SKNode)
      • leftTileNode (SKSpriteNode)
      • middleTileNode (SKSpriteNode)
      • rightTileNode (SKSpriteNode)
    • spriteNode (SKSpriteNode)
The worldNode will be moved to implement the scrolling.
 
 

2. Create the SWIFT project:

 

Create a new Sprite Kit project:

 
SpriteKit Scrolling Tutorial 9
 
SpriteKit Scrolling Tutorial 10
 
 
 

Open Asset Catalogue and add three images (Background, LeftTile, rightTile)

SpriteKit Scrolling Tutorial 11
 

Open GameScene.swift:

 
SpriteKit Scrolling Tutorial 12
 
 

Replace the complete code with this snippet:

(For explanation check the comments inside the code snippet)  

 
//
//  GameScene.swift
//  EndlessScrollingDemo
//
//  Created by STEFAN on 13/11/15.
//  Copyright (c) 2015 Stefan. All rights reserved.
//
 
import SpriteKit
 
class GameScene: SKScene {
 
    // Declare the globaly needed sprite kit nodes
    var worldNode: SKNode?
    var spriteNode: SKSpriteNode?
 
    // store the width of the NodeTiles
    var nodeTileWidth: CGFloat = 0.0
 
    // store the start position of the movement
    var xOrgPosition: CGFloat = 0
 
    override func didMoveToView(view: SKView) {
 
        // Setup static background
        let backgroundNode = SKSpriteNode(imageNamed: “Background”)
        backgroundNode.size = CGSize(width: self.frame.width, height: self.frame.height)
        backgroundNode.anchorPoint = CGPoint(x: 0, y: 0)
        backgroundNode.zPosition = -10
        self.addChild(backgroundNode)
 
        // Setup world
        worldNode = SKNode()
        self.addChild(worldNode!)
 
        // Setup dynamic background tiles
        // Image of left and right node must be identical
        let leftNode = SKSpriteNode(imageNamed: “LeftTile”)
        let middleNode = SKSpriteNode(imageNamed: “RightTile”)
        let rightNode = SKSpriteNode(imageNamed: “LeftTile”)
 
        nodeTileWidth = leftNode.frame.size.width
 
        leftNode.anchorPoint = CGPoint(x: 0, y: 0)
        leftNode.position = CGPoint(x: 0, y: 0)
        middleNode.anchorPoint = CGPoint(x: 0, y: 0)
        middleNode.position = CGPoint(x: nodeTileWidth, y: 0)
        rightNode.anchorPoint = CGPoint(x: 0, y: 0)
        rightNode.position = CGPoint(x: nodeTileWidth * 2, y: 0)
 
        // Add tiles to worldNode. worldNode is used to realize the scrolling
        worldNode!.addChild(leftNode)
        worldNode!.addChild(rightNode)
        worldNode!.addChild(middleNode)
 
        // Setup sprite
        spriteNode = SKSpriteNode(imageNamed: “Spaceship”)
        spriteNode?.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
        spriteNode?.xScale = 0.1
        spriteNode?.yScale = 0.1
        spriteNode?.zPosition = 10
        self.addChild(spriteNode!)
    }
 
    // Implement the scrolling, triggered by swipe gestures
    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
 
        for touch in touches {
 
            // Touch position
            let xTouchPosition = touch.locationInNode(self).x
            if xOrgPosition != 0.0 {
 
                // calculate the new position
                let xNewPosition = worldNode!.position.x + (xOrgPosition – xTouchPosition)
 
                // Check if right end is reached
                if xNewPosition <= -(2 * nodeTileWidth) {
                    worldNode!.position = CGPoint(x: 0, y: 0)
                    print(“Right end reached”)
                // Check if left end is reached
                } else if xNewPosition >= 0 {
                    worldNode!.position = CGPoint(x: -(2 * nodeTileWidth), y: 0)
                    print(“Left end reached”)
                } else {
                    worldNode!.position = CGPoint(x: xNewPosition, y: 0)
                }
 
                // Rotate sprite depending on direction
                if xTouchPosition < xOrgPosition {
                    spriteNode?.zRotation = CGFloat(M_PI/2.0)
                } else {
                    spriteNode?.zRotation = –CGFloat(M_PI/2.0)
                }
 
            }
 
            // Store the current touch position to calculate the delta in the next iteration
            xOrgPosition = xTouchPosition
        }
    }
 
    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        // Reset value for the next swipe gesture
        xOrgPosition = 0
    }
 
    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */
    }
}
 
 
You can download the complete sample from my Github repository.

I’ll show an improved version with a smoother scrolling in part 2. You can support me by downloading my Apps from the Apple AppStore:

AppStore Stefan Josten

That’s all for today.

Cheers,
Stefan