Mega Drive SGDK Megapong

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


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(){
	showText(msg_reset);
	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){
	endGame();
}

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

images/gameover.png

Starting

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;
	updateScoreDisplay();

	ball_pos_x = 0;
	ball_pos_y = 0;

	ball_vel_x = 1;
	ball_vel_y = 1;

	/*Clear the text from the screen*/
	VDP_clearTextArea(0,10,40,10);

	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){
	if(!game_on){
		startGame();
	}
}

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:

while(1)
{
	if(game_on == TRUE){
		moveBall();
		positionPlayer();
	}

	SPR_update();
	VDP_waitVSync();
}

return(0);

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:

showText(msg_start);

This shows our previously defined start message on the screen.

images/gamestart.png

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.

Done!

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.   

Actually…

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

  • 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 occasionally get updates and ramblings! Just enter your email address, prove you're not part of Skynet and you're good to go!



    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

    Make a Space Shooter for the Mega Drive!

    February 24, 2020
    Mega Drive Ramblings

    Patreon Revamps

    January 28, 2020
    Mega Drive Ramblings Patreon

    New SGDK Tutorial: Megarunner!

    November 4, 2019
    Mega Drive Ramblings