Tutorials

Make a Space Shooter

Time for a space shooter. You'll build a ship that flies over a scrolling starfield and fights waves of enemies that shoot back, with explosions, lives, and a title screen.

It works just like the platformer tutorial: play the demo, mess with the code, hit Run. If this is your first time using MDog Engine, do that one first.

MDog Engine is already imported in these demos, and the screen is 256 by 192. For your own game, grab the import line from Getting Started.

1. A Ship and Stars

The ship sits near the bottom and slides left and right. Its position is a Vector for its middle, and it's drawn as a triangle with polygonFill(), which takes a list of corners.

The stars are what sell it. Each one has a position and a speed and moves down every tick. When one falls off the bottom, it jumps back to the top somewhere new, so you never run out. Faster stars are brighter, which makes them look closer. Cheap trick, works great.

2. Shooting

Each bullet is a Vector in a list. Space adds one at the tip of the ship, and every tick they all move up. Once a bullet leaves the screen we take it out of the list, otherwise it'd just keep growing forever.

If you shot every tick while holding space, you'd basically have a laser. So there's a cooldown: it counts down after each shot, and you can only fire again once it hits 0. It's 20 ticks here, which is 8 shots a second (more on this in Timers and Cooldowns).

You might notice the bullet loop goes backwards. That's on purpose. Removing something from a list shifts everything after it down by one, and if you're going backwards, those are things you've already checked. Going forwards, you'd skip one.

Set the cooldown to 5 if you want to feel powerful.

3. Enemies

Now we need something to shoot. Every 70 ticks, an enemy shows up above the screen at a random spot and drifts down.

To know when a bullet hits an enemy, they both get a kickbox, which is what MDog Engine calls a hitbox (see Basics). A SquareKickbox is a rectangle stuck to a Vector, so it moves with it. Bullets and enemies are now objects with a position and a box, made by makeBullet() and makeEnemy(). If a bullet's box is colliding() with an enemy's, both get removed and your score goes up.

The score uses textImage() with the marsfont.png pixel font. For your own game, put the font image in your assets folder (see Add Text).

The break stops checking bullets once one hits, since that enemy's already gone.

4. Explosions

Right now enemies just vanish, which is kind of sad. Let's blow them up instead. Each one bursts into particles from the FX Module: square chunks in fire colors flying out in every direction. Each chunk's direction is a Vector spun a random amount with rotate().

We also shake the screen. translate() shifts everything drawn after it, so shifting by a small random amount each tick makes it shake. The score is drawn after translate(0, 0) so it stays put.

Crank the shake up if you want. Just know that past a certain point it stops being fun and starts being a headache.

5. Waves

One enemy at a time gets old, so now they come in waves. Each wave flies in from the top, lines up in rows, and then the whole group sways side to side. Clear a wave and the next one shows up with two more enemies.

Each enemy remembers its homeX and homeY, its spot in the rows. It flies down until it reaches homeY, and its x is homeX plus a sway from Math.sin(), which smoothly goes back and forth between -1 and 1.

They also shoot back now, a little more each wave. Don't worry, their bullets can't hurt you yet. That's next.

The 24 is how wide they sway and the 90 is how fast.

6. Lives and Game Over

Okay, now their bullets can hurt you. The ship gets its own kickbox, and every hit costs one of its three lives. After a hit you're safe for a second, and the ship blinks so you can tell. Blinking is just skipping the draw on some ticks.

Lose your last life and the ship explodes and you get a game over screen. Same setup as the platformer: each screen is its own function, setActiveFunction() switches between them, and startGame() resets everything. The stars keep moving on every screen, so they live in a function all the screens share.

Next

Some ideas if you want to keep going:

  • Add power-ups that fall from exploded enemies, like a double shot or an extra life.
  • Make some enemies dive down at the ship instead of staying in their rows.
  • Save the high score with localStorage (see Saving Progress).

Or if you're ready for 3D, the racing game tutorial is next.