Scrolling Maps
NOTE:
This tutorial is most likely not compatible with versions of SGDK above 1.70.
Unfortunately, I simply do not have the capacity or ability to update them right now. Read more about it here. Sorry.
One of the biggest revolutions in gaming was the introduction of scrolling. And while scrolling backgrounds are easily implemented in SGDK (see the Megarunner tutorial for an example), scrolling makes a lot more sense when you use it to explore levels that are bigger than a single screen. So, let’s take a look at how to implement such big maps in SGDK!
First of all, let’s set up the resources we’ll need. We’ll of course need the map itself, a tileset to build the map, and a palette to display everything properly. Download the following file, then extract its contents into your res
folder:
Now we need to import stuff into our game. So put the following in your resources.res
file:
TILESET level_tileset "levelmap.png" BEST
MAP level_map "levelmap.png" level_tileset BEST
PALETTE palette_all "levelmap.png"
We’re using a total of three different asset types here. Our tileset is of type TILESET
, which makes sense. This asset will provide the tiles we’ll need to build a level. We’ll call the asset level_tileset
and let SGDK figure out whatever the BEST
compression is.
The map is of type MAP
, which also makes sense. We call it level_map
and pass in levelmap.png
again. As the third parameter, we specify the TILESET that we have just created, so SGDK knows which tiles should be used to create the map. Also, we tell it to use the BEST
compression, whatever that turns out to be.
You might have noticed that we use the same image in both cases. If you take a look at it, you’ll see that it’s basically the entire level! That’s right, the MAP
resource uses images of your level, which it then encodes as a MapDefinition
structure. This might seem a bit strange, but it’s useful because it means we can use the same image for the tileset as well, as it naturally contains all the tiles we’ll need.
If you’re worried that this is inefficient, don’t be. By default, SGDK’s resource compiler actually ignores duplicate tiles! So there is no real downside to using the levelmap as a tileset (at least as far as I can see). You won’t end up with 20 identical sky tiles or anything like that.
Finally, we need a palette. For that we have the type PALETTE
. Again, we just take the levelmap image which obviously contains all the colors we need (at least for the level graphics).
That’s the setup out of the way! Now let’s dive into main.c
and code ourselves a map.
Coding the Map
First, let’s set the palette to use:
PAL_setPalette(PAL0, palette_all.data,DMA);
We use the function PAL_setPalette
to save the color data contained in palette_all
(which we just defined in resources.res
) in PAL0
. As of SGDK 1.65, we also have to specify the transfer method, so watch out for that!
Now let’s load the tileset. This chunk of code does just that:
//Load the tileset and keep track of the index
u16 ind;
ind = TILE_USERINDEX;
VDP_loadTileSet(&level_tileset, ind, DMA);
ind += level_tileset.numTile;
First, we store TILE_USERINDEX
in a new variable called ind
. TILE_USERINDEX
is a define containing the first free index in VRAM; in other words, the first spot not used by the system. We will load the tiles there. Then we load the tileset using the appropriate function. Finally, we increase ind
by the number of tiles that were just loaded, so it points at the next free slot.
We actually won’t use ind
in this project any more. But it’s a good idea to use it when dealing with lots of tiles. Because if we wanted to load more tiles into VRAM later on - which might very well happen when working on a level - we always know where the next empty index in VRAM is! We just have to remember to update ind
whenever new tiles are loaded.
Anyway, now that we have the tileset loaded, we can create the actual map. For that, SGDK offers the aptly titled function MAP_create
:
Map *map;
map = MAP_create(&level_map, BG_A, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, TILE_USERINDEX));
We pass in our MAP resource; tell SGDK what plane to draw it on (BG_A
); specify the palette and whether anything should be flipped; and finally, we pass in the tiles we want to use, which in our case are simply those starting at TILE_USERINDEX
. And that’s actually it, now we have a map!
Buuuut if you compile the game now, you won’t see anything but brown. Keep going, we’ll fix that very soon!
Scrolling
How do we know that the map is actually bigger than the screen? You could believe me that it is, or we could implement scrolling. Let’s do the latter one.
Create two variables before the while(1)
loop:
u32 offset = 0;
u32 scrollDir = 1;
These will just help us make the screen scroll back and forth. Actually scrolling a map is done with the following function, which goes in the beginning of the main game loop:
MAP_scrollTo(map, offset,0);
We just pass in which map to scroll, as well as the x
and y
values we want to scroll it by! Since we’re only scrolling left and right here, we’ll pass in 0 for y
. And by the way, this is the line that makes our map appear on screen in the first place!
But we have to modify offset
to actually scroll the map back and forth, so add this code after the previous line:
offset += scrollDir;
if(offset == 190){
scrollDir = -1;
} else if(offset == 0){
scrollDir = 1;
}
This will just increase offset
every frame and change the direction of scrolling at a certain point. So, the screen will scroll back and forth, giving us a good look at our map.
Oh, and don’t forget to add SYS_doVBlankProcess();
to the end of your while(1)
loop if it’s not there already, otherwise you won’t actually see anything!
Awesome! And very simple to do. By the way, you can have multiple maps at once, like one for the foreground and one for the background. But of course you have to watch out not to blow up the VRAM with too many tiles!
If you've got problems or questions, join the official SGDK Discord! It's full of people a lot smarter and skilled than me. Of course you're also welcome to just hang out and have fun!
Want To Buy Me a Coffee?
Coffee rules, and it keeps me going! I'll take beer too, though.
Check out the rest of this tutorial series!
Comments
By using the Disqus service you confirm that you have read and agreed to the privacy policy.
comments powered by Disqus