Scrolling Maps

Posted September 7, 2021

NOTE:
A new version of SGDK has recently been released. It has probably introduced some breaking changes. If something doesn't seem to be working, post it in the comments and I'll see what I can do to update the tutorial.

Ninja Time!

If you like 90s platformers, check out my new game Chibi Ninja Shino-kun!

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:

Download the Assets

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!

images/scrollingmap.gif

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!

Join my mailing list!

You'll get notified whenever cool stuff happens!

Take It to the Next Level!

Become an excellent patron on Patreon and snatch yourself some kickass perks such as early access, early builds, exclusive updates and more!

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!

  • Creating Graphics for the Mega Drive
  • How to Quickly Generate C Prototype Functions in VSCode
  • Color Swapping
  • 4 Programs For Creating Mega Drive Graphics
  • Editing the Rom Header
  • Simple Game States
  • Creating a Simple Menu
  • Changing The Text Color in SGDK
  • Playing Music in SGDK
  • Converting VGZ to VGM
  • Processing Resets
  • Drawing Tiles From Code
  • Make a Text Crawl, Streets of Rage Style
  • Scrolling Maps
  • Placing Tiles
  • Simple Animated Tiles in SGDK
  • Simple Password System
  • Checking the Region
  • Playing Multiple Music Tracks
  • By using the Disqus service you confirm that you have read and agreed to the privacy policy.

    comments powered by Disqus