Megarunner BONUS - Tile Scrolling

Posted December 16, 2019

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.

Hold up!

If you like 90s platformers, check out my new game Kid Bubblegum!

Know what makes any game better? Parallax scrolling! I know that might sound like an overstatement, because it is. But parallax scrolling is really cool, so let’s add a small parallax effect to our game!


First, let me explain what we’re gonna do here. Remember when I talked about the different scrolling modes? So far we’ve used plane scrolling, but for a parallax effect we’ll have to go one step further and use tile scrolling. As the name implies, this lets us scroll individual rows of tiles, rather than the whole plane at once. By letting rows scroll at different speeds, we create the parallax effect. This will also require some changes in how we deal with the offset. Oh and of course we’ll actually have to add some more tiles that we can scroll. All in all it’s not really difficult. Let’s get going!

Adding Tiles

First let’s add some new tiles that we’ll scroll at a different speed. These will appear to be in front of our old tiles, thus they will scroll faster. Go to the place in main() where we set all our tiles using VDP_fillTileMapRect and VDP_fillTileMapRectInc. Replace the three lines we had with these ones:

VDP_fillTileMapRect(BG_B, TILE_ATTR_FULL(PAL1,0,FALSE,FALSE,1),0,16,32,1); //Floor 
VDP_fillTileMapRect(BG_B, TILE_ATTR_FULL(PAL1,0,FALSE,TRUE,2),0,17,32,2); //Wall

VDP_fillTileMapRect(BG_B, TILE_ATTR_FULL(PAL1,0,FALSE,FALSE,1),0,19,32,1); //Floor in the front
VDP_fillTileMapRect(BG_B, TILE_ATTR_FULL(PAL1,0,FALSE,TRUE,2),0,20,32,8); //Wall in the front

VDP_fillTileMapRectInc(BG_B,TILE_ATTR_FULL(PAL1,0,FALSE,FALSE,3),15,13,2,3); //Lights

This will add another “layer” in front of our current one. It might be a bit hard to visualize, so if you’re having trouble, compile and check the game after adding each line. You’ll see how the whole thing is structured!



If you try the game out now, you’ll see that everything still scrolls uniformly as it did before. Let’s change that!

First, the most obvious thing: Change the scrolling mode from PLANE to TILE:


Next we will need a new variable to handle our new scrolling mode. Add this line before the while(1) loop:

s16 scrollValues[15] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

This line creates an array of s16 values (signed shorts, so integer values that range from -32,768 to 32,767) with a length of 15 members. Why 15? Each value in the array determines the scrolling offset for an individual row of tiles. The upper half of our game screen consists of single-color sky that we won’t have to scroll, so we can ignore those rows. And our actual floor tiles (including the lights) make up a total of …15 rows! That’s 3 rows for the lights, 2 rows for our two floors and 10 rows for the wall tiles.

Alright, before we get to the actual scrolling, define one last variable right after the previous one:

int i = 0;

And also delete the line int offset = 0; as we won’t be needing that variable anymore.

Okay, now let’s dive into the game loop and get those tiles moving! At the beginning of while(1), delete the following two lines:

VDP_setHorizontalScroll(BG_B, offset -= scrollspeed);
if(offset <= -256) offset = 0;

Instead, replace them with this one:


This function takes care of the tile scrolling and is a bit more complex than its plane counterpart. It takes the following arguments:

  1. The plane we want to do our scrolling on
  2. The first tile row we want to scroll; in our case the 13th row from the top, which is where our street lights start
  3. A pointer to the first element of an array with scroll values. In practice you can just put the array variable itself in here
  4. The total number of rows we want to scroll; we have 15 values so we want to scroll 15 rows
  5. The transfer method, which can be either CPU or DMA. CPU is fine for our purposes.

So far so good. But this will actually only scroll our tile rows once, because we have to tell the game to scroll the tiles every frame. So after the previous line, add this for loop:

for(i=0; i<15; i++){
    if(i <= 5){
        scrollValues[i] -= scrollspeed;
    } else{
        scrollValues[i] -= (scrollspeed+1);
    if(scrollValues[i] <= -256) scrollValues[i] = 0;

Let’s break it down. First off, you’ll see that we’re using that variable i that we’ve defined. We’re using it to iterate through all 15 elements of our array.

We want to shift the first 6 rows (remember, arrays in C start at index 0) left by scrollspeed every frame. These rows make up our street lights and the main floor and wall tiles.

The remaining tiles make up the new front layer, which we want to scroll faster; one pixel faster than the regular scroll speed, to be precise.

Finally, just like we did with offset, we check whether a scroll value has gone below -256 and reset it to 0 if it has. This prevents underflows. Check step 3 of this tutorial for a more detailed explanation.

And yeah…that’s pretty much it! Instead of scrolling the entire plane at once, we’re now scrolling each tile row individually. And while this sounds like a lot of extra work, SGDK makes it rather easy for us: Basically we just need to work with an array of values instead of a single value.


Thank you for reading and thank you even more for supporting me on Patreon! It means a lot to me and I hope I can keep doing tutorials like this for a long time to come. Until next time and be excellent to each other!

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 Discord Server!

Hang out, get news, be excellent!

Come hang out!

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!

  • Megarunner 1 - The Framework
  • Megarunner 2 - Tiles
  • Megarunner 3 - Scrolling
  • Megarunner 4 - Player and Obstacles
  • Megarunner 5 - Jumping Math
  • Megarunner 6 - Collision and Score
  • Megarunner BONUS - Tile Scrolling
  • By using the Disqus service you confirm that you have read and agreed to the privacy policy.

    comments powered by Disqus