Tutorial: Scrolling background in Corona SDK

Hello!

Today I’m gonna talk about a scrolling background in Corona SDK. I’m sure you’ve seen this effect in many games and most likely the time has come to implement it in your own one. So, how is this being done?

The first question that might be asked is How many images do I need? The answer is – as many as you wish. I’ve chosen 1, because it’s super easy and fast – there is exactly one graphics and it’s enough.

The second question is In which direction it should scroll? It can be any direction, really, but this tutorial focuses on a vertical top > bottom scrolling. It’s like we’ve been flying higher and higher in sky.

First of all, create a New blank project with ScrollingBackground as a title, and other settings set to default. Then, open config.lua file and make it look like this:

config.lua


application =
{
    content =
    {
        width = 320,
        height = 480, 
        scale = "letterBox",
        fps = 60
    },
}

Here we just set FPS to 60, left other fields as defaults, and removed the rest of unnecessary code.

Below is the background.png that we’re gonna use as our scrolling background. Please, download it and save into the project’s main directory.

example background image

In our newly created project’s directory, open main.lua file. Delete -- Your code here lines and insert the following:


function addScrollableBg()

end

function init()
    addScrollableBg()
end

init()

What we’ve done is just created an empty method and called it from another method – init(). This looks like an overhead right now, but it will all make sense a bit later. Now, lets add some real code, shall we?

Inside addScrollableBg() we will add two rectangles, filled with the same graphics: one set to occupy current phone’s display, and another – on top, by setting its y position to center, minus the height of the display.


local bg1
local bg2

local function addScrollableBg()
    local bgImage = { type="image", filename="background.png" }

    -- Add First bg image
    bg1 = display.newRect(0, 0, display.contentWidth, display.actualContentHeight)
    bg1.fill = bgImage
    bg1.x = display.contentCenterX
    bg1.y = display.contentCenterY

    -- Add Second bg image
    bg2 = display.newRect(0, 0, display.contentWidth, display.actualContentHeight)
    bg2.fill = bgImage
    bg2.x = display.contentCenterX
    bg2.y = display.contentCenterY - display.actualContentHeight
end

Having two images, one on top of another, is great, but they are not moving, and even if there are two of them, we only see one, which isn’t that exciting. To make it move, create a new method and call it moveBg(dt). dt is just a parameter and a delta time, which is basically a compensation value, and we use it to have a smooth scrolling across different devices, so on high-end and low-end devices we have the same scrolling speed. Below you can see a scrollSpeed variable, set to 1.4. You can set any other number, where num > 0, and observe faster or slower scrolling.


local scrollSpeed = 1.4

local function moveBg(dt)
    bg1.y = bg1.y + scrollSpeed * dt
    bg2.y = bg2.y + scrollSpeed * dt

    if (bg1.y - display.contentHeight/2) > display.actualContentHeight then
        bg1:translate(0, -bg1.contentHeight * 2)
    end
    if (bg2.y - display.contentHeight/2) > display.actualContentHeight then
        bg2:translate(0, -bg2.contentHeight * 2)
    end
end

What is happening inside this method, is just an update of both images’s y positions, using translate() method. If the image is below the bottom of a display, we just set its position to be two times higher (because we always have two images and higher means smaller position). To better understand this, I have drawn a very simple illustration:

scrolling bg structure

Now, in order to set bg1’s position on top of bg2, we need exactly those lines – bg1:translate(0, -bg1.contentHeight * 2).

Next, the method moveBg() should be called on every frame update, all the time. This can be achieved with enterFrame, of course. getDeltaTime() has been taken from Delta Time Tutorial and is well-explained there, if you want to find out more.


local runtime = 0

local function getDeltaTime()
   local temp = system.getTimer()
   local dt = (temp-runtime) / (1000/60)
   runtime = temp
   return dt
end

local function enterFrame()
    local dt = getDeltaTime()
    moveBg(dt)
end

function init()
    addScrollableBg()
    Runtime:addEventListener("enterFrame", enterFrame)
end

We’ve also added a runtime listener, so our enterFrame method is linked to the event.

And that’s it! The complete code looks like this:

main.lua


local bg1
local bg2
local runtime = 0
local scrollSpeed = 1.4

local function addScrollableBg()
    local bgImage = { type="image", filename="background.png" }

    -- Add First bg image
    bg1 = display.newRect(0, 0, display.contentWidth, display.actualContentHeight)
    bg1.fill = bgImage
    bg1.x = display.contentCenterX
    bg1.y = display.contentCenterY

    -- Add Second bg image
    bg2 = display.newRect(0, 0, display.contentWidth, display.actualContentHeight)
    bg2.fill = bgImage
    bg2.x = display.contentCenterX
    bg2.y = display.contentCenterY - display.actualContentHeight
end

local function moveBg(dt)
    bg1.y = bg1.y + scrollSpeed * dt
    bg2.y = bg2.y + scrollSpeed * dt

    if (bg1.y - display.contentHeight/2) > display.actualContentHeight then
        bg1:translate(0, -bg1.contentHeight * 2)
    end
    if (bg2.y - display.contentHeight/2) > display.actualContentHeight then
        bg2:translate(0, -bg2.contentHeight * 2)
    end
end

local function getDeltaTime()
   local temp = system.getTimer()
   local dt = (temp-runtime) / (1000/60)
   runtime = temp
   return dt
end

local function enterFrame()
    local dt = getDeltaTime()
    moveBg(dt)
end

function init()
    addScrollableBg()
    Runtime:addEventListener("enterFrame", enterFrame)
end

init()

I hope this tutorial was useful and you have managed to get it work as well as found out something new 😉 Don’t hesitate and leave a comment below in case of any questions.

Like and share:

Published by

Tonia Tkachuk

I’m an Android Developer, writing code for living and for fun. Love beautiful apps with a clean code inside. Enjoy travelling and reading.