Pablo Garcia

Apps for iPhone, iPad, Apple TV and Apple Watch

Spritekit - Background Scrolling - II

Jun 30, 2019

So, once we've achieved background scrolling (to the right), we are going to move forward and do this:

  • Detect when the user touch the right/left side of the screen
  • Update nodes in the linkedlist

Once we achieve this, we'd have something like this:

Screen touch

  • We have to override touchesBegan function and locate where the user has touched the screen.
extension MainScene: UIGestureRecognizerDelegate {

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

        for touch in touches {
            let position = touch.location(in: self)

            if position.x < self.frame.width/2 {
                self.backgroundScroll?.changeDirection(direction: .left)
            } else {
                self.backgroundScroll?.changeDirection(direction: .right)


Update nodes in the linkedlist

  • We have modified our update function to change the position of all nodes in the LinkedList. Depending on scroll direction, we'll take the head or the tail of the linkedlist and update all node's positions.
public func update(deltaTime: TimeInterval) {

    guard !linkedBackgrounds.isEmpty else {

    if direction == .right {
        if let head = linkedBackgrounds.first {
            let headSprite = head.value
            headSprite.position = CGPoint(x: headSprite.position.x-CGFloat(deltaTime)*speed, y: headSprite.position.y)
            var node = linkedBackgrounds.first
            while node?.next != nil {
                let previous = node
                node = node?.next
                node?.value.position = CGPoint(x: (previous?.value.position.x)!+(previous?.value.frame.width)!,
                                               y: (previous?.value.position.y)!)
            if spriteIsOutOfBounds(sprite: head.value) {
                let node = linkedBackgrounds.remove(node: head)
                linkedBackgrounds.append(value: node)
    } else {
        if let tail = linkedBackgrounds.last {
            let tailSprite = tail.value
            tailSprite.position = CGPoint(x: tailSprite.position.x+CGFloat(deltaTime)*speed, y: tailSprite.position.y)
            var node = linkedBackgrounds.last
            while node?.previous != nil {
                let next = node
                node = node?.previous
                node?.value.position = CGPoint(x: (next?.value.position.x)!-(node?.value.frame.width)!,
                                               y: (next?.value.position.y)!)
            if spriteIsOutOfBounds(sprite: tail.value) {
                let node = linkedBackgrounds.remove(node: tail)
                linkedBackgrounds.appendBeginning(value: node)

Maybe we could optimize this function, but for now it's ok.

You have the code here. Hope you enjoy it!

And that's all folks!! See you in part three!!!