Learn how to make an endless runner for the Sega Mega Drive using SGDK! I highly recommend working through the Megapong Tutorial first, as that explains a lot of the basics of MD coding.

Megarunner 4 - Player and Obstacles


Update: Fixed a small error when importing the rock graphic. Thanks to Thiago for pointing it out!

Alright, we got the background moving, now we need a player sprite to complete the illusion. Of course we could create very long levels and have the player actually run through them, but it is way more efficient to fake endless running by just scrolling the background past the player.

Importing the Image

First, download the player image here. If you take a look at it you’ll see that the image contains 3 different sprites of our player character:

images/sheet.png

This is what’s called a spritesheet. We will be using the images as frames of animation in a minute. For now, create a folder called sprites in the res folder of your project, then put the player spritesheet in there. Good? Good.

Now open up the resources.res file in the res folder and add the following line to import the player graphic:

SPRITE runner "sprites/player.bmp" 2 2 NONE 20

As you can see we’re importing the file as a SPRITE under the name runner. We also specify that the sprite is 2 tiles wide and 2 tiles high. But wait…the actual player.bmp is 32x32 pixels big, which would be 4x4 tiles! What gives? We actually only tell SGDK how big one sprite is, which is 16x16 px in our case. The resource compiler then automatically imports and processes all the sprites within an image file (3 in our case).

NONE is the compression we want to use. Finally, 20 tells SGDK that we want our animations to run at 20 frames per second. Yes, you set the animation speed while importing!

Adding the Sprite

Now that we’ve imported the graphic, let’s put the player on screen. At the top of main.c define these variables to store our player, as well as the x and y positions:

Sprite* player;
const int player_x = 32;
int player_y = 112;

Then we’ll extract the palette from the image. Feel free to put this line after our previous call to VDP_setPalette where we got the colors of the tiles:

VDP_setPalette(PAL2, runner.palette->data);

Next, in main(), after all our code dealing with the background tiles, add the player by typing in the following code:

SPR_init(0,0,0);
player = SPR_addSprite(&runner,player_x,player_y,TILE_ATTR(PAL2,0,FALSE,FALSE));

Finally, add the following line within the if(game_on == TRUE) block in the main loop:

SPR_update();

All this code will initialize the sprite engine, add the player sprite and store a reference in player, then update the sprite engine every frame so that the player sprite is actually drawn on screen. As you can see we’re using PAL2 for the player, instead of PAL1 as we did for the tiles. Again, this is kind of wasteful, but it keeps thing simple and our project doesn’t come close to reaching the limits of the Mega Drive anyway.

Animations

Now that we have the player on screen, let’s animate the little guy! At the very top of main.c, after the includes, add the following two defines:

#define ANIM_RUN	0
#define ANIM_JUMP	1

This will make it easier for us to deal with animations, as we won’t have to remember the number of each one. And how do we actually trigger these animations? Put the following line right after player = SPR_addSprite(...):

SPR_setAnim(player,ANIM_RUN);

Pretty self-explanatory, isn’t it? We use SPR_setAnim to tell the sprite engine what sprite should use which animation. The animation will then automatically start playing, we don’t have to start it manually or anything like that.

Obstacles

We’ve imported one sprite, so we might as well import another, right? Let’s add the obstacle to the game. Download the file here and put it in res/sprites. Then import it by adding the following line to resources.res:

SPRITE rock "sprites/rock.bmp" 1 1 NONE 0

The rock sprite is a simple 1x1 tile affair with no animation, so importing it is rather straightforward.

Now at the top of main.c, after the player variables, add this chunk of code:

/*Obstacle stuff*/
Sprite* obstacle;
int obstacle_x = 320;
int obstacle_vel_x = 0;

We’ll just use a single obstacle that we reuse over and over for now. These variables will track the position and velocity of the obstacle.

In main(), add the obstacle sprite right after you’ve added the player:

obstacle = SPR_addSprite(&rock,obstacle_x,128,TILE_ATTR(PAL2,0,FALSE,FALSE));

Afterwards update the sprite engine once:

SPR_update();

Note that we’re using PAL2 again! If you compile the game now you won’t actually see the obstacle, because we put it at x-coordinate 320, which is the right edge of the screen. This is because we of course want it to move to the left, so let’s do that now!

In the main loop, add the following lines after the code that makes the background scroll:

//Move the obstacle
obstacle_vel_x = -scrollspeed;
obstacle_x = obstacle_x + obstacle_vel_x;
if(obstacle_x < -8) obstacle_x = 320;

We’re doing three things here. First, we set the x-velocity of the obstacle to negative scrollspeed, so that the obstacle moves exactly as quickly as the background. Then we update the x-position of the obstacle by adding the velocity to it. And finally we check if the obstacle has gone past the left edge of the screen (remember, the sprite is 8 pixels wide), in which case we put it back outside the right edge, so that it can take another shot at making the player stumble.

Did you think that’s all we had to do? Then you fell into my cunning trap! None of this code will have any visible effect until we’ve called this function, right at the end of the if(game_on == TRUE) block:

SPR_setPosition(obstacle,obstacle_x,120);

Remember: Variables like obstacle_x are just variables that we create for ourselves, the sprite engine doesn’t actually do anything with them until we explicitly tell it to!

images/rockscroll.gif

Now if you compile the game you should have an infinitely moving rock obstacle. It enters from the right, phases through the player, exits to the left, then wraps around back to the right. Our runner dude doesn’t seem very interested in it though, so next time we’ll start working on collisions and letting him jump!

If you have any questions, comments or criticism, post them in the comments below or reach out to me on Twitter @ohsat_games! Special thanks to Stephane Dallongeville for creating SGDK and everyone in the SGDK Discord for their help and keeping the dream alive!

Download the source code

All patrons on Patreon get the complete source code for this tutorial, as well as other perks such as early access! Become a Patron!
Just Want to Buy Me a Coffee?

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
  • Get Words in Your Inbox!

    Be oldschool and sign up for my newsletter to get updates! Just enter your email address, prove you're not part of Skynet and you're good to go!



    Powered by CleverReach. I will not send you spam or sell/give your email address to someone else.  You can of course unsubscribe at any time. By clicking the subscribe button above, you confirm that you have read and agreed to our privacy policy.

    By using the Disqus service you confirm that you have read and agreed to the privacy policy.

    comments powered by Disqus

    Related Posts

    Streets of Rage 2 Design Docs

    A few years ago, Yuzo Koshiro posted a pile of old game design documents for Bare Knuckle 2 aka Streets of Rage 2 on the Ancient blog to commemorate the release of Streets of Rage 2 3D on the Nintendo 3DS. These documents gave a deep insight into the game’s inner workings, technical aspects, designs and even some cut content. They were an awesome resource for one of the most awesome games ever created.

    Read More

    Make a Space Shooter for the Mega Drive!

    It’s time for another SGDK tutorial series! After doing a single player Pong game and an endless runner, it’s time to reach for the stars… and make a space shooter! Apart from things like scrolling and animating sprites, this new series will show you how to deal with multiple entities and their collisions, how to randomly generate backgrounds and more! This project builds upon the previous tutorials, so if you’re new to SGDK programming and have not done those yet, I highly recommend starting with Megapong.
    Read More

    Patreon Revamps

    Hey there, what’s up? Things are continuing to evolve, as I’ve now updated my Patreon to give patrons more perks! Apart from early access to new tutorials and posts, the biggest one is probably the ability to peek behind the scenes…and there will be a lot to peek at in the coming months! This year I’m writing and submitting my MA thesis, meaning that I will have to do more stuff to make ends meet.
    Read More