Tile-based scrolling
In this little tutorial we will cover a widely used technique used to draw game backgrounds: tilemaps. Using this technique, our backgrounds are going to be made up of pieces (tiles) that, drawn together, will allow us to create bigger and more complex levels without using huge amounts of memory. The basic idea is to have a 2d value table, where each value represents a tile. Using that table, we will know what tiles to draw at a certain position, given some basic parameters like the map width, height and the current coordinates of an imaginary viewport. Don't worry if you don't understand these terms right now, I'll explain them in more detail as we start coding.
So, let's start with some variables:
Code: Select all
-- our tiles
tile = {}
for i=0,3 do
tile[i] = love.objects:newImage( "gfx/tex"..i..".jpg" )
end
love.graphics:setFont(love.objects:newFont(love.default_font, 12))
-- map vaiables
map_w = 20
map_h = 20
map_x = 0
map_y = 0
map_offset_x = 30
map_offset_y = 30
map_display_w = 14
map_display_h = 10
tile_w = 48
tile_h = 48
Now, the next thing we have to do is set up a handful of map and tile variables to be able to draw the map correctly. This ones should be pretty self-explanatory: besides height and width of the tiles and our tilemap, we also have the size of the region of tiles to display. The two offset variables are used to define the point where we will start drawing out tilemap. You migh want to play a little with these variables to see their effects.
Now, to the map structure itself:
Code: Select all
map={
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 1, 0, 0, 2, 2, 2, 0, 3, 0, 3, 0, 1, 1, 1, 0, 0, 0, 0, 0},
{ 0, 1, 0, 0, 2, 0, 2, 0, 3, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0},
{ 0, 1, 1, 0, 2, 2, 2, 0, 0, 3, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
{ 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0},
{ 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 2, 2, 2, 0, 3, 3, 3, 0, 1, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0},
{ 0, 2, 0, 0, 0, 3, 0, 3, 0, 1, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0},
{ 0, 2, 0, 0, 0, 3, 0, 3, 0, 1, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0},
{ 0, 2, 2, 2, 0, 3, 3, 3, 0, 1, 1, 1, 0, 2, 2, 2, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
Let's continue:
Code: Select all
function draw_map()
for y=1, map_display_h do
for x=1, map_display_w do
love.graphics:draw( tile[map[y+map_y][x+map_x]], (x*tile_w)+map_offset_x, (y*tile_h)+map_offset_y )
end
end
end
Obviously, you have to call draw_map() on your draw() callback. If you run your example right now, you should see our little tilemap on screen. You can't do any scrolling right now, but we'll get onto that right now, adding the following to our update() callback:
Code: Select all
function update( dt )
if love.keyboard:isDown( love.key_up ) then
map_y = map_y-1
end
if love.keyboard:isDown( love.key_down ) then
map_y = map_y+1
end
if love.keyboard:isDown( love.key_left ) then
map_x = map_x-1
end
if love.keyboard:isDown( love.key_right ) then
map_x = map_x+1
end
-- check boundaries
if map_x < 0 then
map_x = 0
end
if map_x > map_w-map_display_w then
map_x = map_w-map_display_w
end
if map_y < 0 then
map_y = 0
end
if map_y > map_h-map_display_h then
map_y = map_h-map_display_h
end
end
Now go and run your script. Isn't LÖVE cool? You bet it is, congratulations on making your first tilemap scroller!
Closing words
While this little example should be enough to get you up and running, there are quite a few possible enhancements:
- Writing our maps by hand is a little stupid, we should make them with tools like Tiled and load them in our game.
- Drawing characters inside the tilemap.
- Fine scrolling: As you probably noticed, the map scrolls tile by tile and you probably don't want that if you need to move your characters/object pixel by pixel.
- Multi-layered maps: Most real tile engines are able to render more than one layer. Together with fine scrolling, you would be able to scroll a near layer at a certain speed and move another one behind it more slowly.
- Character to map collisions.
-- END OF TUTORIAL
Teh screen:
Teh filez:
http://www.cloverpunk.com.ar/tehstuffs/love-tut2.love
EDIT: Fixed typo, thanks Sardtok n_n
EDIT2: Seems like my hosting is acting up. I'll annoy the hell out of a few support guys...