Foreground/Background Scrolling Implementation

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
verilog
Citizen
Posts: 97
Joined: Thu Nov 03, 2011 3:15 am
Contact:

Foreground/Background Scrolling Implementation

Post by verilog »

Hello guys!
Your help would be very much appreciated on this matter, let me explain. Days ago I was trying to figure out a simple and effective method for implementing a scrolling system, one of my constraints is that I would like to scroll unique images, not tilesets.

So, I thought I would need to load the full image once, then, create some sort of screen buffer of the same size as the screen and, finally, update this buffer with the data matching the current position of the scene in the full image.

I searched around for a while, and FrameBuffers seemed the way to go in order to implement this kind of stuff, unfortunately, my current PC does not support FrameBuffers, so I’m looking for an alternative way of implementing an efficient scrolling method.

Currently, I’m considering two possible solutions: one based on ImageData Objects and one based on Quads.

I tried to code a simple test based on the former method, the basic idea is this:
  • 1. Load the image data with newImageData.
    2. Create a buffer, or “canvas”, same size as the screen with newImageData.
    3. Paste the current chunk of the image, corresponding to the actual scene, to the “canvas” with ImageData:paste
    4. Convert the “canvas” data to a drawable, final image
    5. Draw the final image on the screen
This is the code for love.load():

Code: Select all

function love.load()
	sWidth = 800 --Screen Width
	sHeight = 600 -- Screen Heigth
	love.graphics.setMode(sWidth, sHeight, false, false, 0)
	print('setMode Done')
	
	platformImage = love.image.newImageData("foreground.png")
	screenCanvas = love.image.newImageData(sWidth, sHeight)
	print('Loaded Resources')
	
	iWidth = platformImage:getWidth()
	iHeight =  platformImage:getHeight()
	
	speed = 300	
	x = 0
	y = 0
	print('Loaded Variables')
end
love.update()

Code: Select all

function love.update(dt)

   if love.keyboard.isDown("right") then
      x = x + (speed * dt)
	  print('Scroll right: '..x)
   elseif love.keyboard.isDown("left") then
      x = x - (speed * dt)
	  print('Scroll left: '..x)
   end

   screenCanvas:paste(platformImage,0,0,x,y)
end
And love.draw()

Code: Select all

function love.draw()
	finalImage = love.graphics.newImage(screenCanvas)
	love.graphics.draw(finalImage, 0, 526)
	love.graphics.print("FPS: "..love.timer.getFPS() .. '\nMem(kB): ' .. math.floor(collectgarbage("count")), 650, 20)
end
Can you help me spot and correct my mistakes? I’m pretty sure something similar to this has to be done, but I’m getting horrible framerate drops with my implementation, any suggestion to help me nail down the problem would be greatly appreciated. I haven’t tested out the same idea using Quads instead, mainly because I don’t know if this would be a good idea. If you have another suggestion for achieving an efficient scrolling, I’d löve to hear it!

I've attached the love file below, but please, be aware that is somewhat unestable, and will end up eating a good chunk of memory. Scroll foreground with "right" and "left" arrows.
Attachments
scrollTest.love
(44.4 KiB) Downloaded 418 times
User avatar
runyonave
Prole
Posts: 27
Joined: Tue Dec 06, 2011 2:06 am

Re: Foreground/Background Scrolling Implementation

Post by runyonave »

I haven't used canvas, so I can't help you much there. But the way I would do it is have a tile sheet with all the random images on it. Then make a quad out of that tile sheet. So for example, if you had a tile sheet with 20 images and placed those in a quad, you would access them by; quad[1], quad[2] etc. Now you have numerical values to call each image. So all you have to do now is make a function that gets a number between 1 and 20. Then just have the function show the image quad of what ever number comes up.

E.g.

function get_random_image()

1. plant random seed
2. get random number from 1 to 20
3. place the random number in a variable -> random_image
4. get the quad image for that number -> quad[random_image]
5. scroll the image
6. loop this function to continuously get a string of random images

end
User avatar
rhezalouis
Party member
Posts: 100
Joined: Mon Dec 07, 2009 10:27 am
Location: Indonesia
Contact:

[Response]Scrolling Background Implementation Sample

Post by rhezalouis »

verilog wrote:... I would like to scroll unique images, not tilesets.
In that case, I wonder why should you paste a portion of your platform-image to a buffer ImageData before drawing it; instead of just simply create an Image of your platform. The process to create a new image from that buffer at every frame (as in your code snippet below) spends relatively much resources.

Code: Select all

finalImage = love.graphics.newImage(screenCanvas)
There are several possible solutions to your requirements:
  1. As mentioned before, simply load your platform to an image and draw it.
    verilog-scrolltest.love
    LÖVE 0.7.2
    (41.72 KiB) Downloaded 420 times
    I have altered your key test procedure so that the your application don't have to check it on every frame but only when the key is pressed.
    P.S. Btw, could you display the image in your computer? I have set the platform-image size to 8192 x 128 to avoid PO2 syndrome, but it is still rendered as a white box.
  2. Split the platform-image to several ImageData, convert them to Image, put then in a table. Then draw the platform-image portion for the current screen-width, before, and after.
    verilog-scrolltest2.love
    LÖVE 0.7.2
    (41.73 KiB) Downloaded 402 times
    P.S. There is a mistake in the formula to determine the x position for the platform (when x > 0) and I can't find it yet. Therefore, I strongly discourage you to use the code as is. Haha. However, I have put a limit in the keypressed-callback conditional to patch this issue :roll:.
N.B. You need to have a more proper dimension (to define the platform's position) so that it would be easier to be used by another parts you would add in your application; e.g. currently you need to have a negative x to go further to the right (in reverse to the LÖVE X axis). Maybe it's better if you inverse the sign and adjust the formula in the drawing function so that the 'game-logic' is aligned with the axis you are comfortable with.

Good luck ^^.
Last edited by rhezalouis on Sat Jan 28, 2012 4:06 am, edited 1 time in total.
Aargh, I am wasting my posts! My citizenshiiiip... :o
User avatar
verilog
Citizen
Posts: 97
Joined: Thu Nov 03, 2011 3:15 am
Contact:

Re: Foreground/Background Scrolling Implementation

Post by verilog »

Hello guys, first, let me thank you for taking the time to read this and help me out with this issue, I REALLY appreciate it :)

Runyonave: Thank you man, I contemplated a similar solution: Split up a very large image into n Quads, n would be the actual width of the screen. I would basically set up a counter to track the position of the screen and map that counter to the number of the Quad needed, then, draw that particular Quad. However, I’m worried about the number of the quads needed for this method and their resource consumption. Thanks a lot for your input, man!

Rhezalouis: Man, I really appreciate what you have done, really. I’ve studied the code you kindly provided, and solution # 2 is really what I was looking for. So let me see if I've got this right:

During the load phase, you load the full image, then, you split the image in i parts with screen width and store each part in a table. Then, in the draw phase you draw the current image part, based on the screen position. You actually draw 3 images: current image-1, current image and current image+1, right? That’s exactly what I was trying to achieve. Just one question, though: I’m kinda worried of the resource consumption it takes to store each part of the image in the table, specially if I want to scroll large images, what do you think?

Again, I appreciate what you have done, mad props to you, man! :crazy:

P.S. The platform image shows fine for me, in solution # 1 however, all I also see is a white box :P
User avatar
The Burrito
Party member
Posts: 153
Joined: Mon Sep 21, 2009 12:14 am
Contact:

Re: Foreground/Background Scrolling Implementation

Post by The Burrito »

Is that the ground from Earthworm Jim, "For Pete's Sake"?
Also, just for a quick reference as far as massive images go, many video cards can't handle things bigger than 2048X2048, and if you're using something that is less than 512px tall I suggest breaking it up into 512X512 chunks otherwise there can be a heck of a lot of overhead.

For In The Dark the foregrounds and backgrounds are painted in photoshop and usually come to me at resolutions around 2000X10000, I dice them up into 512X512 chunks and then stick em in a directory (I have a function that handles all the positioning based on the file names). The game then loads the image data and x,y offsets and renders them like this:

Code: Select all

for i,v in ipairs(backgrounds) do
	if v.x>cam.x-520 and v.x < cam.x+cam.w+520 then 
		love.graphics.draw( v.img, (v.x-cam.x)*cam.z, (v.y-cam.y)*cam.z, 0,cam.z*v.s,cam.z*v.s, 0,0)
	end
end
v.s is a scalar and cam.z is for zooming so obviously they're unneeded in most games. Changing cam.x and cam.y will cause it to scroll, cam.w is the current horizontal resolution.
It's pretty fast, but it's still a lot of data when I run it on my netbook.
User avatar
verilog
Citizen
Posts: 97
Joined: Thu Nov 03, 2011 3:15 am
Contact:

Re: Foreground/Background Scrolling Implementation

Post by verilog »

The Burrito wrote:Is that the ground from Earthworm Jim, "For Pete's Sake"?
Yes, it is. That's an excellent example of what I’m aiming for. :awesome:

So burrito, you load all the image chunks at once? Let’s say you have a 7680x512 image, you split it in 15 chunks and then load all the 15 parts at once? Or load only the parts that are being currently processed? (e.g. the current, previous and next frames)
Thanks for the advice man.

Rhezalouis, I’ve modified the code a bit so you can now scroll to the right and left with the corresponding arrow directions and without reversing the LÖVE X axis
Attachments
verilog-scrolltest3.love
LÖVE 0.7.2
(41.87 KiB) Downloaded 392 times
User avatar
The Burrito
Party member
Posts: 153
Joined: Mon Sep 21, 2009 12:14 am
Contact:

Re: Foreground/Background Scrolling Implementation

Post by The Burrito »

I load them all up front, loading dynamically is certainly feasible, but if it is technically possible for the camera to ever scroll super fast it's probably going to cause a bit of slowdown. I'm doing foregrounds and backgrounds and they're stacked 3-5 rows high, so I could on occasion have 10 images that would all pop up at once, way too much to be loaded from file in 1 frame. Since you only have a single row thats not really an issue, but then again it's not really a big deal to load them all at the beginning either.

If you've got photoshop you can give the slice tool a try to automatically subdivide the image, it's a bit buggy for big images though. I modified a gimp script I found online to handle the divisions.

You may not have interest in it, but you can actually do the exact same thing for foregrounds and backgrounds to create basic parallax scrolling, just multiply the x offset by 1.5 or something for foregrounds and .5 or something for backgrounds,
User avatar
verilog
Citizen
Posts: 97
Joined: Thu Nov 03, 2011 3:15 am
Contact:

Re: Foreground/Background Scrolling Implementation

Post by verilog »

You may not have interest in it, but you can actually do the exact same thing for foregrounds and backgrounds to create basic parallax scrolling, just multiply the x offset by 1.5 or something for foregrounds and .5 or something for backgrounds
I actually would like to include this kind of scrolling in my project, thank you for your comments man. BTW, I'm sure you read this everyday, but your game is f****g awesome man, your work is really inspiring, keep it up! :awesome:
User avatar
The Burrito
Party member
Posts: 153
Joined: Mon Sep 21, 2009 12:14 am
Contact:

Re: Foreground/Background Scrolling Implementation

Post by The Burrito »

Thanks! I've been working on it for a long time, (about 2 years, it's at about 5k lines excluding map files now) hopefully it'll be done in the next few months, the programming is pretty much finished, I'm just working on maps and art related stuff now.

Also with the foregrounds and backgrounds you'll probably want to have looping ones. You can either repeatedly draw the same image, or you can use quads, which is what I do:

Code: Select all

fgTex.i = love.graphics.newImage(img)
fgTex.i:setWrap( "repeat", "clamp" )
fgTex.d = 2 --this is the scroll speed scalar
fgTex.q = love.graphics.newQuad( 0, 0, cam.w, fgTex.i:getHeight( ), fgTex.i:getWidth( ), fgTex.i:getHeight( ) )
setViewport creates the actual scrolling action, then just have to draw it on screen.

Code: Select all

fgTex.q:setViewport( cam.x*fgTex.d, 0, cam.w, fgTex.i:getHeight( ) )
love.graphics.drawq( fgTex.i, fgTex.q, 0, fgTex.y-cam.y)
It's letting the video card do most of the work, so I think it's a little more efficient (I haven't actually done any tests so can't say for sure).
User avatar
verilog
Citizen
Posts: 97
Joined: Thu Nov 03, 2011 3:15 am
Contact:

Re: Foreground/Background Scrolling Implementation

Post by verilog »

Thanks Burrito, your advices are gold to me! I actually was trying to devise a simple method for implementing a looping background; this will definitely come in handy! A little question, do you have any advice for implementing collision checks on irregular shaped platforms?

E.g. consider the “for pete’s sake” platform image, it is quite irregular, so, I was thinking on a method for checking collisions with this kind of terrain, I thought I’d have to describe the platforms (floor) as a series of slopes that bound the player’s vertical position, I’m still working on the idea but the main issue I have here is to let the player walk on a highly irregular platform.

Anyway man, I appreciate your comments, cheers!!
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 7 guests