Learn how to make a space shooter 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.

Megalaga 8 - Spam Protection

Posted April 16, 2020

Last time I mentioned that there is a potential issue concerning our game which was related to the bullet pool. And now I’m going to reveal the secret (and of course fix the issue)!

The issue stems from the fact that both the player and all enemies draw from the same bullet pool. The player isn’t actually limited in how many bullets they can fire; before a bullet is fired, we only check whether bulletsOnScreen < MAX_BULLETS is true. This means that if the player keeps firing continuously, there will almost never be a free bullet for an enemy to shoot, because the player is using all bullets available in the pool!

This of course makes the game super easy, which is not what we want. I mean, if we wanted an easy game, we wouldn’t have let the enemies shoot in the first place, right? So let’s fix that.

Start off with a new define and a new variable near the top of main.c:

#define MAX_PLAYER_BULLETS 3
u16 shotByPlayer = 0;

The variable shotByPlayer will keep track of how many of the currently active bullets have been shot by the player. We will compare this value to MAX_PLAYER_BULLETS whenever the player tries to fire. This way some of the bullets in the pool will be reserved for the enemies.

Let’s move on to shootBullet() now to implement this! You’ll see that first of all, we check whether a bullet has been fired by the player and store that result in fromPlayer. Then we check whether we have reached the maximum amount of bullets allowed on screen. We want to leave both of these checks unchanged, but we will add a new one right at the start of the if (bulletsOnScreen < MAX_BULLETS) body:

if(fromPlayer == TRUE){
    if(shotByPlayer >= MAX_PLAYER_BULLETS){
        return;
    }
}

So now the player can only fire if a) there is still room on screen for another bullet and b) if MAX_PLAYER_BULLETS hasn’t been reached yet. If the player has fired all of their allotted bullets, we simply return out of shootBullet() without firing anything. The player will then have to wait until one of the bullets they have fired hits an enemy or goes offscreen.

But for this to work we need to keep shotByPlayer updated. Let’s start doing this in shootBullet() while we’re still here!

After we use reviveEntity to revive the bullet we want to fire, we check whether the bullet is going to be fired by the player to set the velocity accordingly. Looks like the perfect spot to increase our counter! So add a line to make the statement look like this:

if(fromPlayer == TRUE){
    b->vely = -3;
    shotByPlayer++;
} else{ ... }

This way shotByPlayer will only get incremented if the player shoots a bullet, not an enemy. But of course we’ll also have to decrease the value somewhere! We’ll do this twice. The first time is in positionBullets(). Inside of the if-statement where we check whether the current bullet has left the top of the screen, add a line to make it look like this:

if (b->y + b->h < 0)
{
    killEntity(b);
    bulletsOnScreen--;
    shotByPlayer--;
}

This will free up a bullet in the pool when the player misses an enemy. And now we of course have to decrease the value when the player doesn’t miss! This will happen inside of handleCollisions().

Inside the innermost if-statement body of that function (so inside of if (collideEntities(b, e)){}), add the line so it looks like this:

//...
enemiesLeft--;
bulletsOnScreen--;
shotByPlayer--;
//...

And there we go, that’s all we need to do! Now we keep track of how many bullets the player has fired and prevent them from firing more once the limit has been reached. This way there is no way to cheese the game by spamming bullets and keeping the pool empty for the enemies. You can of course decrease MAX_PLAYER_BULLETS to make the game tougher on players if you want!

Our game is even more polished now, but one thing is still missing: Sound! It wouldn’t be a space shooter if you didn’t hear the pew pew of lasers and the krakoom of exploding enemies. So next time we’ll talk about sound drivers and how to make our game less quiet! Until then, be excellent to each other!

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!

  • Megalaga 1 - Space
  • Megalaga 2 - Entities
  • Megalaga 3 - Enemies
  • Megalaga 4 - Enemy Movement and Input
  • Megalaga 5 - Bullets
  • Megalaga 6 - Collision and HUD
  • Megalaga 7 - Enemy Bullets
  • Megalaga 8 - Spam Protection
  • Megalaga 9 - Sound
  • Megalaga BONUS - Powerup
  • 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