Megarunner 3 - Scrolling

Posted November 18, 2019

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.

Hold up!

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

Welcome back! Last time we drew a background with a floor and even some street lights. This time we’ll get things moving by scrolling the background to create the illusion of endless running!

Preparations

As usual, we have to do a bit of preparation work. First off we’ll define a new constant at the top of the file that will store the speed at which our background will scroll.

const int scrollspeed = 2;

Next up we’ll set our desired scrolling mode. In main(), add this line after VDP_setPlanSize(32,32);:

VDP_setScrollingMode(HSCROLL_PLANE,VSCROLL_PLANE);

What does this actually do? First of all, note that we’re giving the function two values: The first one sets the desired mode for horizontal scrolling (HSCROLL) the second one for vertical scrolling (VSCROLL). But what is a mode? SGDK (and the Mega Drive hardware) supports multiple ways of scrolling. The values that we have chosen (with _PLANE) tell SGDK that we want to scroll the entire plane at once. You could also scroll tiles or lines, which are slightly more advanced modes that allow you to create parallax effects and such. But we simply want to scroll the entire plane for now.

One more thing before we get to the actual scrolling. We will need a variable that stores the scrolling offset, which I’ll explain in a second. Define this variable right before your main game loop starts:

int offset = 0;
while(1){
    //game loop stuff
}

Keep Scrollin' Scrollin' Scrollin' Scrollin'

Alright, let’s get scrolling! As you might expect, SGDK offers us a function that will handle the scrolling. Put this one right at the beginning of your game loop:

VDP_setHorizontalScroll(BG_B, offset -= scrollspeed);

The first argument tells the function which plane we want to scroll. Since we put our tiles on background plane BG_B, that’s of course the one we want. The second argument passes in the offset that we want. This basically tells SGDK how far we want our plane to be moved: In our case, we want to move it by scrollspeed. But why are we keeping track of offset?

It might seem obvious to some and confusing to others, depending on what game engines you’ve worked with in the past. In some cases you tell the engine “I want the background to constantly scroll at speed X” and then it just happens. In SGDK this works differently! We are not passing in the desired speed at which we want the plane to scroll, but the actual distance we want it to move each frame. This means that we have to keep track of how far the plane has already scrolled, so that we can adapt that value for the next frame.

In the first frame, we have offset == 0. Our call to VDP_setHorizontalScroll subtracts scrollspeed from that, which results in offset == -2. This offset is then applied to the plane, meaning that it will be moved two pixels to the left. In the next frame, offset is reduced again to offset == -4, meaning the plane is now rendered another 2 pixels to the left (and 4 pixels left from where it originally was). So basically we have to tell SGDK every frame where our plane is currently located, which, in our case, is always two pixels further to the left than in the previous frame.

Underflowing

“But wait!” I hear you cry. “Wouldn’t that mean that offset will keep decreasing forever”? Yes it does! And this is bad, because that would eventually cause an underflow and mess everything up. True, the game would have to go on for quite a while before we’ve reached the limit of what an int can take, but it’s better to be safe than sorry. So right after VDP_setHorizontalScroll(BG_B, offset -= scrollspeed); add the following line:

if(offset <= -256) offset = 0;

This resets offset so that it doesn’t become too small. Wonder why I picked 256? Well…try to figure it out yourself for a minute! Remember that plane size…?

Okay, I’ll tell you the answer. We set our plane size to be 32 tiles wide. One tile is 8px x 8px, meaning that our plane is 32 * 8 = 256 pixels wide. So if the plane has moved 256 pixels to the left (that is, when offset == -256), it will have moved one entire plane-length – and since it loops (remember how planes are “stitched together”?), it will basically be right back to where it started. So by resetting offset when it hits 256 we get smooth scrolling without any skips! (And just for fun, feel free to try out other values and see what happens).

That was a lot of theory, but if you compile the game now you should see that we have a scrolling background! Just look at it go. Feel free to make racing car noises! Neeeeoooown…

images/scrolling.gif

And here’s a question!

As you might remember, we’ve only placed one streetlight in our scene…but now, sometimes there are two on screen at the same time! Do you know why?

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