Scrolling Background

Hey everyone just want to say thanks for all of the help I have been getting here it’s nice to see that corona has good support even for those of us who haven’t bought a license yet.

My question this time is how do you do a scrolling background. I have across a few posts on how to do it. Only one of them have almost worked for me. The problem I am getting is that it only goes through two of the images and stops.

[code]
local image1 = display.newImage(“images/Lvl_2/Level_2_BG_1.png”,0,0)
local image2 = display.newImage(“images/Lvl_2/Level_2_BG_2.png”,480,0)
local image3 = display.newImage(“images/Lvl_2/Level_2_BG_3.png”,480,0)
local image4 = display.newImage(“images/Lvl_2/Level_2_BG_4.png”,480,0)
local image5 = display.newImage(“images/Lvl_2/Level_2_BG_5.png”,480,0)
local image6 = display.newImage(“images/Lvl_2/Level_2_BG_6.png”,480,0)
local image7 = display.newImage(“images/Lvl_2/Level_2_BG_7.png”,480,0)
local image8 = display.newImage(“images/Lvl_2/Level_2_BG_8.png”,480,0)
local image9 = display.newImage(“images/Lvl_2/Level_2_BG_9.png”,480,0)
local image10 = display.newImage(“images/Lvl_2/Level_2_BG_10.png”,480,0)

transition.to(image1, { time= 10000, delay= 1500, x= -(image1.width* 0.5)} )
transition.to(image2, { time= 10000, delay= 1500, x= (image2.width * 0.5) } )
transition.to(image3, { time= 10000, delay= 1500, x= (image3.width * 0.5) } )
transition.to(image4, { time= 10000, delay= 1500, x= (image4.width * 0.5) } )
transition.to(image5, { time= 10000, delay= 1500, x= (image5.width * 0.5) } )
transition.to(image6, { time= 10000, delay= 1500, x= (image6.width* 0.5) } )
transition.to(image7, { time= 10000, delay= 1500, x= (image7.width * 0.5) } )
transition.to(image8, { time= 10000, delay= 1500, x= (image8.width * 0.5) } )
transition.to(image9, { time= 10000, delay= 1500, x= (image9.width * 0.5) } )
transition.to(image10, { time= 10000, delay= 1500, x= (image10.width * 0.5) } )

[code]
Any advise will be much appreciated. [import]uid: 49863 topic_id: 19155 reply_id: 319155[/import]

Well, one vague overview way, your best bet will be to put all your images in a table. Tables are your friend. Something like this (with errors in there I’m sure):
[lua]local levels = {}

levels[1] = “images/Lvl_2/Level_2_BG_1.png”
levels[2] = “images/Lvl_2/Level_2_BG_2.png”[/lua]
etc…
–empty table to hold rendered levels

Then loop thru the table and render them:
[lua]renderedLevels = {};

for i=1,#levels do
renderedLevels[i] = display.newImageRect(levels[i], 480, 0)
renderedLevels[i].id = i – give it an ID so you know what you’re talking about.
renderedLevels[i].x = 2000 ; – put it off the screen
–renderedLevels[i].isVisible = false; – you could also hide it.
end[/lua]

Then make the first one scroll:
[lua]local moveBg = function() end --Look ahead declaration.

local getNextBG = function(obj)
–Call it for our next one:
local nextId = obj.id + 1
if(nextId > #levels) then
–ur out of levels, do something…
else
moveBG(renderedLevels[nextId])
end
–you should probably remove the old one, unless you need it.
end

moveBG = function(imageToMove)
transition.to(imageToMove, { time= 10000, delay= 1500, x= -(imageToMove * 0.5), onComplete=getNextBG} )
end

–make the first one go:
moveBg(renderedLevels[1])[/lua]

That being said, I’ve only been doing this for a couple of weeks, so I’m sure some of the more seasoned people will have a better answer… [import]uid: 19193 topic_id: 19155 reply_id: 73898[/import]

You could also probably only render 1 image at a time, and render the next one as needed to free up some memory… [import]uid: 19193 topic_id: 19155 reply_id: 73899[/import]

i think you can drop all those transition.to lines.

this should work:

  1. create a group, like local mycam = display.newGroup()
  2. declare all your images, like you have
  3. make sure your images X values are correct, i.e. so they fit next to each other
  4. add your images to the group like mycam:insert(image1) etc etc.
  5. add a runtime listener for enterframe to call some function to update the scrolling and then create the scrolling function to simply update your groups X value, that should scroll everything in that direction.
    [import]uid: 97789 topic_id: 19155 reply_id: 73919[/import]

@bragbase I was with you till number five lol. Either I am not understanding what you are saying or I just don’t know how to it. [import]uid: 49863 topic_id: 19155 reply_id: 75148[/import]

Hi,

you can download and run this, change the simulator to use iPad, i hardcoded some Y values and don’t think it will show properly emulating anything else.

anyways, here’s the download link, hope it adds some value :slight_smile:

https://docs.google.com/open?id=0B1dS1I8gymzOZjdjMDMwYmUtN2MyNC00NTMzLTkyZjAtZTg3MWM4ZDAyNGY4

cheers
[import]uid: 97789 topic_id: 19155 reply_id: 76089[/import]

Thank you bragbase. I am still having troubles though. I am using this function from your code and I followed your steps of 1 - 4 correctly. I am getting the first two backgrounds and then blackness in the background. The same thing happens when the if statement is taken out or left in. Any ideas?

[code]
local function canWeScroll(event)
bgGroup.x = bgGroup.x - 1
–[[if image1.x > 800 then
bgGroup.x = -image1.x + 800
end–]]

end
[import]uid: 49863 topic_id: 19155 reply_id: 76119[/import]

I would have to look at your code as a whole to see why its clonking out, can you zip up and send it [import]uid: 97789 topic_id: 19155 reply_id: 76909[/import]

I am not sure how to do that. I will post the code for the entire mini game here. If you can’t figure it out like that just tell me how to upload the zip file and I will do that.

[code]
module(…, package.seeall)

–====================================================================–
– SCENE: Fishbowl Game
–====================================================================–

–[[

  • Version: 0.1
  • Made by Ninja Carnival Team @ 2011

******************

  • INFORMATION
    ******************

  • Fishbowl game

–]]

new = function ( params )

– Imports
local ui = require ( “ui” )

– Groups
local localGroup = display.newGroup()
local bgGroup = display.newGroup()
local scoreLayer = display.newGroup()
– Declare Variables
local gameIsActive = true
local toRemove = {}
local score = 0
local halfPlayerWidth
local toRemoveFish = {}

– start physics
local physics = require(“physics”)
local sprite = require(“sprite”)
physics.start()
physics.setGravity(0,0 )

– Enemy graphics held in memory
local textureCache = {}
textureCache[1] = display.newImage(“images/Lvl_2/fish.png”)
textureCache[1].isVisible = false
local halfEnemyWidth = textureCache[1].contentWidth * .5

– Pre-loads our sounds
swimming = audio.loadSound(“audio/Lvl_2/swimmingfinal.wav”)
music = audio.loadStream(“audio/Lvl_2/LevelTwoSongFinal.wav”)

– Display Objects
local contentWidth = display.contentWidth

local image1 = display.newImage(“images/Lvl_2/Level_2_BG_1.png”,0,0)
local image2 = display.newImage(“images/Lvl_2/Level_2_BG_2.png”,480,0)
local image3 = display.newImage(“images/Lvl_2/Level_2_BG_3.png”,480,0)
local image4 = display.newImage(“images/Lvl_2/Level_2_BG_4.png”,480,0)
local image5 = display.newImage(“images/Lvl_2/Level_2_BG_5.png”,480,0)
local image6 = display.newImage(“images/Lvl_2/Level_2_BG_6.png”,480,0)
local image7 = display.newImage(“images/Lvl_2/Level_2_BG_7.png”,480,0)
local image8 = display.newImage(“images/Lvl_2/Level_2_BG_8.png”,480,0)
local image9 = display.newImage(“images/Lvl_2/Level_2_BG_9.png”,480,0)
local image10 = display.newImage(“images/Lvl_2/Level_2_BG_10.png”,480,0)

–[[transition.to(image1, { time= 10000, delay= 1500, x= -(image1.width* 0.5)} )
transition.to(image2, { time= 10000, delay= 1500, x= (image2.width * 0.5) } )
transition.to(image3, { time= 10000, delay= 1500, x= (image3.width * 0.5) } )
transition.to(image4, { time= 10000, delay= 1500, x= (image4.width * 0.5) } )
transition.to(image5, { time= 10000, delay= 1500, x= (image5.width * 0.5) } )
transition.to(image6, { time= 10000, delay= 1500, x= (image6.width* 0.5) } )
transition.to(image7, { time= 10000, delay= 1500, x= (image7.width * 0.5) } )
transition.to(image8, { time= 10000, delay= 1500, x= (image8.width * 0.5) } )
transition.to(image9, { time= 10000, delay= 1500, x= (image9.width * 0.5) } )
transition.to(image10, { time= 10000, delay= 1500, x= (image10.width * 0.5) } ) --]]

scoreText = display.newText(score, 0, 0, native.systemFont, 19)
scoreText:setTextColor(0,0,155)
scoreText.x = 100
– BUTTONS

– Functions
local function onCollision(self, event)
if self.name == “swimming” and event.other.name == “fish” and gameIsActive then
score = score + 1
scoreText.text = score
–get a sound effect for this event
table.insert(toRemove, event.other)

elseif self.name == “swimming” and event.other.name == “squid” and gameIsActive then
gameEnd()

elseif self.name == “swimming” and event.other.name == “urchin” and gameIsActive then
gameEnd()
end

end

local function spawnUrchin( event )
local urchin = display.newImage(“images/Lvl_2/urchin_final_56.png”)
urchin.name = “urchin”
physics.addBody(urchin, “kinematic”, {density=1.0, friction=0.5, bounce=0.0, radius= 30})
urchin.y = 320
urchin.x = math.random(50,480)
transition.to(urchin, {time = 20000, y = -320})
print (urchin.y)
return urchin
end

local function spawnFish( event )
local fish = display.newImage(“images/Lvl_2/fish.png”,50,60)
fish.name = “fish”
physics.addBody(fish, “kinematic”, {density=1.0, friction=0.5, bounce=0.0, radius= 30})
fish.x = math.random(480, 480)
fish.y = math.random(50, 320)
transition.to(fish, {time= math.random(2000,4000), x=-250})

return fish
end

function newSwimmingSprite()

swimming = sprite.newSprite(spriteSet2)
swimming:prepare(“default”)
swimming.isHitTestable = false
print (“gotit”)
return swimming
end

local function movePlayer( event )

if event.phase ~= ended and gameIsActive then
transition.to( swimming, { time=1500, x = event.x, y = event.y } )
swimming.velocity = 0
print(swimming.y)
end

–print (“moved player”)

end

local function spawnPlayer( event )

swimming = newSwimmingSprite()
swimming.name = “swimming”

physics.addBody(swimming, “dynamic”, {density=1.0, friction=0.5, bounce=0.0, radius= 15})
swimming.collision = onCollision
swimming:addEventListener(“collision”, swimming)
Runtime:addEventListener(“touch”, movePlayer)
swimming:play()

print (“spawnedPlayer”)
end

function coordUpdate( event )

if swimming.x > 460 then swimming.x = 460
print(swimming.x)
end

end

local function canWeScroll(event)
bgGroup.x = bgGroup.x - 1
if image1.x > 800 then
bgGroup.x = bgGroup.x - 1
end

end

function gameEnd( event )

gameIsActive = false
swimming:pause()
end

– PARAMETERS

– Listener

– INITIALIZE
local initVars = function ()
– Inserts

bgGroup:insert(image1)
bgGroup:insert(image2)
bgGroup:insert(image3)
bgGroup:insert(image4)
bgGroup:insert(image5)
bgGroup:insert(image6)
bgGroup:insert(image7)
bgGroup:insert(image8)
bgGroup:insert(image9)
bgGroup:insert(image10)

scoreLayer:insert(scoreText)
– Positions

– Colors

– Listeners

swimming = sprite.newSpriteSheet( “swim_sheet.png”, 64, 31 )
spriteSet2 = sprite.newSpriteSet(swimming, 1, 4)
sprite.add( spriteSet2, “default”, 1, 4, 1000, 0 )

spawnPlayer()
swimming.x = display.contentWidth * 0.5
swimming.y = display.contentHeight * 0.5
end

– Initiate variables
initVars()

– Update
local update = function ( event )
local timeLastEnemy = 0

if gameIsActive then
for i = #toRemove, 1, -1 do
toRemove[i].parent:remove(toRemove[i])
toRemove[i] = nil
end
for i = #toRemoveFish, 1, -1 do
remove(toRemoveFish[i])
toRemoveFish[i] = nil
end

end

end

audio.play(music, {loops = -1})
timer.performWithDelay(math.random(500, 1000), spawnFish, 0)
timer.performWithDelay(2500, spawnUrchin, 0)
Runtime:addEventListener(“enterFrame”, update)
Runtime:addEventListener(“enterFrame”, coordUpdate)
Runtime:addEventListener(“enterFrame”, canWeScroll)
– MUST return a display.newGroup()
return localGroup

end [import]uid: 49863 topic_id: 19155 reply_id: 76933[/import]

Do you need a constant velocity or a variable velocity focused on the player movement? [import]uid: 81091 topic_id: 19155 reply_id: 77045[/import]

don’t see anywhere where you update the left coords of the BG images, they all on top of each other starting at 480px
local image1 = display.newImage(“images/Lvl_2/Level_2_BG_1.png”,0,0)
local image2 = display.newImage(“images/Lvl_2/Level_2_BG_2.png”,480,0)
local image3 = display.newImage(“images/Lvl_2/Level_2_BG_3.png”,960,0)
local image4 = display.newImage(“images/Lvl_2/Level_2_BG_4.png”,1140,0)

etc etc.

then the canwesroll, u need to move the whole bg group when ur player gets close to the edge.

the other thing is I see you also spawn fish to a max of 480px, when you use the scroll method of the sample i gave you, the X keeps increasing as scrolling happens, run my sample and see the printed X value.

Maybe there is another way that will work better for you [import]uid: 97789 topic_id: 19155 reply_id: 77103[/import]

Sorry, for meddling, but that’s exactly what I’m looking for, too. I have one single background picture and I want to use it for an endlessly scrolling background with the velocity depending on the player movement. Any suggestions for doing this? My first attempt was an array of size 2 holding two copies of my background picture. The first one was filling the entire screen, the second one was right next to the first one outside of the screen. Then I tried to use the transition.to method to move both background objects simultaneously to the left, and as soon as one of them would disapper on the left side of the screen I would adjust the x parameter to put it on the right side again:

local background = {}

background[0] = display.newImageRect(“background.png”, 480, 778)
background[0]:setReferencePoint(display.BottomLeftReferencePoint)
background[0].x = 0

–background[1] = display.newImageRect(“background.png”, 480, 778)
–background[1]:setReferencePoint(display.BottomLeftReferencePoint)
–background[1].x = 480

local repositionBackground = function(tile)
print(“Starting next transition”)
tile.x = 480
transition.to(tile , {time = 20000, x = -480, onComplete = repositionBackground})
end

print(“Starting 1. transition”)
transition.to(background[0] , {time = 10000, x = -480, onComplete = repositionBackground})
–transition.to(background[1] , {time = 20000, x = -480, onComplete = repositionBackground})

I put some lines into comments cause I was trying to isolate the error I got. I see “Starting 1. transition” in the terminal window and the background moves out of the left border of the screen, then I see “Starting next transition” in the terminal and the background reappers on the right side and moves to the left side. But after it disappers for the second time on the left side, nothing else happens. I don’t see another call of the repositionBackground method.

Any ideas what’s wrong with my code? Or is there even a better way for doing this, also respecting changing scrolling speeds? [import]uid: 24216 topic_id: 19155 reply_id: 77782[/import]

@ devsalad no there is not a reason to use velocity yet…
@ bragbase. So far the fish don’t seem to be causing a problem. This is a constantly scrolling back ground so I am a bit confused by what you are saying on the canWeScroll function. Aside from that everything seems to be working except for one thing now. I don’t know how to stop the scrolling when the last image is reached.
@ coolflyer. I am a bit confused as to what you are doing. Why are you scrolling like that on one image? I would suggest just making more copies of the background and doing what I am doing for a constant scrolling background. [import]uid: 49863 topic_id: 19155 reply_id: 77800[/import]

The scrolling continues coz of enterframe listener, that fires all the time (at whatever ur framerate is) and calls canwescroll. Use a listener like tap or touch to call canwescroll [import]uid: 97789 topic_id: 19155 reply_id: 77806[/import]

@crazypsycho6973052: Why would I need more than two copies of my background for smooth scrolling? I guess I should be fine with two. In my example code I commented one of the two background copies cause I was trying to isolate the error I got. [import]uid: 24216 topic_id: 19155 reply_id: 77813[/import]

@bragbase. Yeah I want it scroll like that with enterFrame but once I am on the last image I want to stop. I was thinking something like if bgGroup == image10 then Runtime:removeEventListener(“enterFrame”,canWeScroll). But I can’t seem to get that to work. Also thanks for all of the help you have given me to this point you are a real life saver. [import]uid: 49863 topic_id: 19155 reply_id: 78172[/import]

After what I learned to this point I went back to my original code. It would work the way I want now except for one issue. The screens are moving too fast and overlapping. There seems to be an issue with time and delay if anyone has any ideas I would appreciate it.

[code]
local image1 = display.newImage(“images/Lvl_2/Level_2_BG_1.png”,0,0)
local image2 = display.newImage(“images/Lvl_2/Level_2_BG_2.png”,480,0)
local image3 = display.newImage(“images/Lvl_2/Level_2_BG_3.png”,960,0)
local image4 = display.newImage(“images/Lvl_2/Level_2_BG_4.png”,1140,0)
local image5 = display.newImage(“images/Lvl_2/Level_2_BG_5.png”,1620,0)
local image6 = display.newImage(“images/Lvl_2/Level_2_BG_6.png”,2100,0)
local image7 = display.newImage(“images/Lvl_2/Level_2_BG_7.png”,2580,0)
local image8 = display.newImage(“images/Lvl_2/Level_2_BG_8.png”,3060,0)
local image9 = display.newImage(“images/Lvl_2/Level_2_BG_9.png”,3540,0)
local image10 = display.newImage(“images/Lvl_2/Level_2_BG_10.png”,4020,0)

transition.to(image1, { time= 20000, delay= 4500, x= -(image1.width* 0.5)} )
transition.to(image2, { time= 20000, delay= 4500, x= (image2.width * 0.5) } )
transition.to(image3, { time= 20000, delay= 4500, x= (image3.width * 0.5) } )
transition.to(image4, { time= 20000, delay= 4500, x= (image4.width * 0.5) } )
transition.to(image5, { time= 20000, delay= 4500, x= (image5.width * 0.5) } )
transition.to(image6, { time= 20000, delay= 4500, x= (image6.width* 0.5) } )
transition.to(image7, { time= 20000, delay= 4500, x= (image7.width * 0.5) } )
transition.to(image8, { time= 20000, delay= 4500, x= (image8.width * 0.5) } )
transition.to(image9, { time= 20000, delay= 4500, x= (image9.width * 0.5) } )
transition.to(image10, { time= 20000, delay= 4500, x= (image10.width * 0.5) } ) [import]uid: 49863 topic_id: 19155 reply_id: 78981[/import]

Thanks again for everyone’s help. Turns out it was just one background causing issues half way through the scrolling background. I put a short delay on it and now there is smooth scrolling. Got a new issue but I will post it in a new thread. [import]uid: 49863 topic_id: 19155 reply_id: 82743[/import]