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 3 - Enemies

Posted March 2, 2020

Last time we defined a struct of type Entity and used it to create a player. Now it’s time to throw some enemies into the fray! It ain’t a shooter without somethin' to shoot at, after all. Luckily our Entity struct will make that rather easy for us, because this way, each entity will keep track of its own position, velocity and other values.

And to be extra lazy clever, we’ll put all enemy entities into an array, so we can deal with them more easily in bulk. So at the top of main.c (but after our struct definition) define the following:

#define MAX_ENEMIES 6
Entity enemies[MAX_ENEMIES];

In our game we’ll have a maximum of 6 enemies on screen at once, but you can of course change that number. We’ll write the code in such a way that we’ll just need to change this one #define in order to modify the number of enemies.

We’ll also want to keep track of how many enemies there currently are on screen. So after the above definitions, add this line:

u16 enemiesLeft = 0;

Alright, now to actually create all those enemy entities. Since we’re doing a simple game with a simple setup, we’ll use a for loop for this. Create one after creating the player entity in main():

/*Create all enemy sprites*/
Entity* e = enemies;
for(i = 0; i < MAX_ENEMIES; i++){

Before the loop we’re defining a pointer e which is assigned the entire enemies array. This will make the pointer point at the first value in that array (that’s a behavior of the C language). We will use this pointer to reference the current enemy entity and to loop through them.

Now might be a good time to brush up on your pointer skills, by the way. There’s just no escaping those things.

Anyway, you might have noticed that we’re reusing the variable i that we had defined when we were drawing our tiles. There’s no need to create another variable for iteration here, as i isn’t used for anything else. Saving memory is fun!

Now to actually make our loop do things. First, let’s set some basic values of our current enemy:

e->x = i*32;
e->y = 32;
e->w = 16;
e->h = 16;
e->velx = 1;
e->health = 1;

Note that now we’ll have to use the arrow operator (instead of a dot) to access an item in a struct, since e is a pointer. For your information, e->x is equivalent to (*e).x. Nifty.

The x position will be different for each enemy. We’re placing them in a row with a bit of space in between. The y-position, width and height will be the same for all enemies. We’re also setting the x-velocity to 1, so that our enemies start moving right when the game starts. The health of enemies will be 1 at the start, meaning that they are alive (remember that we’re not using health bars, we just care whether an entity is alive or dead).

Now to add sprites. Remember that the Entity struct has a Sprite* item in it, which will store our sprite.

e->sprite = SPR_addSprite(&ship,e->x,e->y,TILE_ATTR(PAL2,0,TRUE,FALSE));

Note that the third argument of TILE_ATTR is TRUE. This will flip the sprite so that the enemy is pointing downwards. “But wait a minute!” you might think here. “We’re using palette 2?” Yes we are, so we need to define it. So up in main(), where we grab the palette data from our tiles, add another line so we end up with this:

VDP_setPalette(PAL1, background.palette->data);
VDP_setPalette(PAL2, background.palette->data);

Changing Colors

Okay, so…remember how I said that we’d be using the same palette (PAL1) for both tiles and sprites, so we could be “efficient”? Well…that’s getting thrown out the window now. I’m doing this to show you a cool trick in a second. Usually you would do things differently, but it’s easier to explain this way… and after all, we’re making a very basic game here. But anyway, let’s finish up the enemy loop first.

We’ll give each enemy a name. Generate it like this:

sprintf(e->name, "En%d",i);

This will call each enemy “En” plus its number (En1, En2, …). As I said, we won’t be using these names, but they’re good for debug purposes so I wanted to show you how to add them.

Finally, we’ll increment enemiesLeft by 1 since this enemy is now done. And even more finally, we point the pointer e at next enemy in the array so that the loop can keep going.


And that’s it! Now our loop creates 6 enemies that are positioned in a row near the top of the screen. You might have noticed that we’re using the same graphic for the enemy ships as we’ve used for the player ship. And yes, that’s the reason we just called the image ship. However, having the same sprites for both would look boring, so let’s use that trick I told you about to spice things up a little. We’ll use a palette swap to make the enemy ships look different. Add this line after the for-loop has closed:


The helper function RGB24_TO_VDPCOLOR converts colors from a RGB hex value to a format the Mega Drive VDP can process. We set the color at index 34 to 0x0078f8, which is a blue color. Index 34 is stored in PAL2 and just so happens to be the orange color of the ship sprite. So with this line we’re switching that color to blue, making the enemies look different without actually having to load another sprite. That saves on resources!

Now of course this approach is a bit heavy-handed here. We’re using PAL2 only for this one color, wasting the other 15. And it would be better to use unique sprites for the enemies anyway, because palette swaps can look kind of cheap. But I wanted to show you this trick, because it’s very useful and a common technique in retro game development. Feel free to change the other colors in PAL2 to make things slightly less wasteful and to make the enemies look even more interesting. The indexes for PAL2 are 32–47.

That was a lot of code. Compile the game now and you should see a row of enemies menacing our player!


Although they don’t actually move… We’ll fix that next time. We’ll also be adding bullets to the game, so that you can shoot the enemies down. Until then and be excellent to each other!

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!

  • 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

    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