In this tutorial series you will learn how to make a simple single-player Pong-like game for the Sega Mega Drive using SGDK! If you just want to see the full source code, you can get it from Github.

Megapong 9 - Game Over

Posted October 14, 2019

Time to finish this game of ours! This time we’ll add a fail state and some general polish to complete the Megapong experience. Let’s jump right into it!

Making Things Easier for Us

First, let’s make things a bit easier for ourselves. We’ll have to show some messages on screen soon and we can create the following helper function to help us out:

/*Draws text in the center of the screen*/
void showText(char s[]){
	VDP_drawText(s, 20 - strlen(s)/2 ,15);

As you can see, this function takes a string (that is, a char[]) and then draws this string in the center of the screen using VDP_drawText and the power of math. This spares us from always having to specify the x- and y-positions of the text we want to draw.

Game Over

Now to implement a fail state. We’ll need a global variable to track the current game state, so let’s define one (outside of main()). We’ll also take this opportunity to write and store the messages we want displayed when the game starts/ends. Put these lines somehwere at the top of main.c near your other variable definitions:

game_on = FALSE;
char msg_start[22] = "PRESS START TO BEGIN!\0";
char msg_reset[37] = "GAME OVER! PRESS START TO PLAY AGAIN.";

Now to define what should happen when the game ends, that is when the ball is lost. We’ll do that in a function:

void endGame(){
	game_on = FALSE;

Define this function after showText() since we’re using it in this one! The function should be pretty self-explanatory: We display our reset message, then set game_on to FALSE. So when does the game end? When the ball hits the lower bound of the screen, so we’ll call this function in moveBall(). Replace the following lines…

} else if(ball_pos_y + ball_height > BOTTOM_EDGE){
	ball_pos_y = BOTTOM_EDGE - ball_height;
	ball_vel_y = -ball_vel_y;

…with this one:

else if(ball_pos_y + ball_height > BOTTOM_EDGE){

Now the ball won’t bounce off the bottom edge anymore, meaning players can actually lose!



That’s the ending taken care of, but a game also needs a proper beginning. Right now the game starts the moment you open it, which isn’t ideal. But that’s where our game_on variable will come in handy once again! Let’s define a counterpart function to endGame():

void startGame(){
	score = 0;

	ball_pos_x = 0;
	ball_pos_y = 0;

	ball_vel_x = 1;
	ball_vel_y = 1;

	/*Clear the text from the screen*/

	game_on = TRUE;

This function resets our score and HUD, positions the ball at (0,0) and then launches it by setting its velocity. It then calls VDP_clearTextArea which, as the name implies, clears an area of the screen of text. To be more specific, it clears a rectangle starting at tile coordinates (0,10) with a width of 40 tiles and a height of 10 tiles. We call this so any messages on the screen – msg_start or msg_reset – are cleared before the game begins. And finally, the function sets game_on to TRUE.

Okay, so where do we call this function? Well, remember our joypad callback function? Let’s put it in there, so it gets called whenever players press the Start button! In void myJoyHandler, add the following before checking for BUTTON_RIGHT and BUTTON_LEFT:

if(state & BUTTON_START){

Pressing the Start button will now start our game, but only if it’s not running already. However: If you compile the game and try it out now, you’ll notice that the ball starts moving immediately, whether you’ve pressed Start or not. This is because we’re missing one step: We have to tell the game to only move our entities when the game is actually running, meaning if game_on == TRUE. Modify your while(1) loop in main() so it looks like this:

	if(game_on == TRUE){



That way the ball and paddle will only be moved when the game has really begun, and stop moving once it’s over.

We’re almost done! Let’s just add some icing to the cake by welcoming the player to our game. In main(), after drawing the score label and updating the score, add this:


This shows our previously defined start message on the screen.


Since we’re already calling VDP_clearTextArea(0,10,40,10); in startGame() that’s all we need to do, as the message will be deleted once the game starts.


Congratulations, you have now developed your first Mega Drive game! It’s not going to set any sales charts on fire, but you made a Mega Drive game. How cool is that?

So what now? Well, you are free to improve upon the game! You could for example add a lives system to make it a bit easier for players. The ball currently also always starts at the same spot and goes in the same direction, which is a bit boring…maybe you could randomize that? There’s lots of stuff to do, so let your imagination run wild! And if you come up with something cool, share it in the comments below!

I’d like to thank you very much for reading. I hope you’ve found this tutorial helpful! If you want to see more tutorials like this one, consider becoming a patron on Patreon! You will get project files for each step of a tutorial and more.   


Oh, and as an exclusive bonus to my Patrons there will actually be one more step for this tutorial next week, where we implement a cool little flashing effect. A pledge of $2 will get you this bonus step, as well as bonus steps for every future tutorial! So if you want to push your skills even further, consider chucking me a few bucks on Patreon!

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!

Download the Project Files!

All patrons on Patreon get the complete source code for this tutorial, as well as other perks such as early access! And Patreon support also ensures that I can keep working on tutorials like this one. Become a Patron!
Just Want to Buy Me a Coffee?

Check out the rest of this tutorial series!

  • Megapong 1 - Hello Mega Drive World!
  • Megapong 2 - Setting Up The Environment
  • Megapong 3 - Importing Resources
  • Megapong 4 - Palettes
  • Megapong 5 - Sprites
  • Megapong 6 - Input and Paddles
  • Megapong 7 - Collisions
  • Megapong 8 - Score and HUD
  • Megapong 9 - Game Over
  • Megapong BONUS - Flashing!
  • 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

    HaxeFlixel Tutorials!

    If you’ve popped over to the tutorial section recently you might have noticed that I’ve added my very first HaxeFlixel tutorial! It shows how to implement a simple, pixel-perfect 2D water shader which I used for Go! Go! PogoGirl. But a few of you might be wondering what a HaxeFlixel is. Well, it’s a 2D game framework that is as powerful as it is underrated! It runs on the (also underrated) Haxe language, is extremely well documented, open source, and has built-in functions for almost anything you’d need.
    Read More

    Streets of Was

    As I’m sure many of you will remember, the original Streets of Rage for the Mega Drive had multiple endings. The real canonical ending has you beat the crap out of Mr. X, thereby ending his reign of terror forever (yeah, right). However, if you confronted Mr. X with a buddy in tow, a new possible path unlocked. A quick refresher is in order. When you confront Mr. X he will ask you to join his organization.
    Read More

    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