Make Your Own Arcade Space Shooter


Make Your Own Arcade Space Shooter

Create your own version of Asteroids in GameMaker.

We’ll build this game in three simple steps:

  1. Program the ship to move
  2. Make space rocks explode
  3. Finish your game

Download GameMaker and let’s begin!

[ 1 Move Your Ship / 2 Destroy Rocks / 3 Finish Your Game ]

How to Create a New Project

Open GameMaker. You'll see a “New” button – click on it.

undefined

Here you can start with a blank project, or choose a template.

For this game, let's use the "Space Rocks" template. This gives you all the images for this tutorial.

undefined

Enter a "Project Name", and hit "Let's Go!".

You're now in your project!

undefined

The Asset Browser on the right contains all your assets. You'll now see four Sprites, which are images you can use in your game.

There’s “spr_player”, the ship you’ll fly, “spr_bullet”, which you’ll fire from your ship, and two rocks, which you’ll destroy.

How to Use The Asset Browser

In the same Asset Browser, we want to create some objects. An object is how you bring an image to life, by programming it to move, shoot, or do anything you need it to.

Your ship, rocks, and even the bullets you fire are created as objects. We’ll put these in the “Objects” group in the Asset Browser, which is currently empty.

undefined
Create a new Object

undefined
Rename it to obj_player

Right-click on the “Objects” group, and select “Create -> Object”. Change its name from “Object1” to “obj_player”.

Press F2 to rename your selected object, or right-click on it and select “Rename”.

How to Edit an Object

undefined

Your new object has an editor. Here you change its properties, and program it, which we’ll do very soon.

Every object needs a sprite – otherwise how would you see it?

Click where it says “No Sprite”, and from under the “Sprites” group, select spr_player.

undefined

We need some more objects now. Just like you created obj_player, create three more objects:

  1. obj_bullet: This is the bullet your ship fires.
    Set the sprite to spr_bullet.

  2. obj_rock: This is the rock you’ll destroy.
    Set the sprite to spr_rock_big, as every rock will start big, and shrink as you shoot it.

  3. obj_game: This is a “silent” object that will manage your game.
    It doesn’t need a sprite.

undefined

These are all the objects you need! Let’s now place these inside a level.

How to Make a Level in GameMaker

Each “level” in GameMaker is a room asset. Look in the Asset Browser – there’s one already there for you:

undefined

Double-click on it. The “Room Editor” will open, where you’ll build your level.

Before doing anything, I want to resize the room to make it a 1000x1000 square.

How to Resize a Room in GameMaker

Look at the lower-left corner of the window - you'll see an "Inspector" window.

undefined

Here, set the Width and Height of the room to 1000. You can use a different size.

If you don't see these options, go into your Asset Browser and click on Room1. They should be visible while the room is selected.

How to Place Objects in a Room

undefined

Look at the left panel in the Room Editor: there are two layers created by default, “Instances” and “Background”.

  1. Instances: This is an instance layer. Your objects go here, just like cereal goes into a bowl.
  2. Background: This is a background layer. Change the background colour or apply an image.

Click on the “Instances” layer to select it – this is where your objects will go:

undefined

From the Asset Browser, drag obj_player and place it in the room.

Your player ship is in the room now, as an “instance” – you can place multiple “instances” of any object in the room!

Do this with the rocks – drag obj_rock into the room multiple times, until you have around six instances:

undefined

The stage is set for the play. We just need to teach the actors their roles.

How To Move The Ship

undefined

If you run the game right now (press F5 or the “Play” button at the top) your game will open, but it’ll be as still as a frozen lake at night.

Your objects are there, your room is there, but nothing is programmed to move or do anything.

Let’s work on that.

How to Use Events in GameMaker

undefined

On pressing the “up arrow” key, we want to push the player ship forward.

In your Asset Browser, double-click on obj_player.

Look at its Object Editor – specifically the “Events” window.

undefined

Click on “Add Event”, and select “Step”.

You might be asked to choose between GML Code and GML Visual.

Choose GML Code if you've done programming before, or GML Visual if you're new.

This tutorial will cover both options, so you can choose whichever option you prefer.

undefined

Make your choice, and enable “Don’t ask again for this project.”

What is the Step event?

After making your choice above, you'll see the window for the Step event open up.

undefined
GML Code window for the Step event

An object has many events. Each event has its own unique time when it runs.

For example, you brush your teeth in the morning. Then you breathe pretty much all day, every second.

undefined

If you were a GameMaker object, you would brush your teeth in the "Create" event, and breathe in the "Step" event.

That's because the "Create" event is the first event to run for an instance, and it only runs once. The "Step" event then runs all the time in every single frame while the instance exists.

We’re going to program this “Step” event to move the ship, as it's a continuous thing that must happen, akin to breathing.

How to Program an Event

Soon I’ll show you some things to add into the “Step” event. The way you add them differs in GML Code and GML Visual.

If you’re using GML Visual, search for the relevant actions in the Toolbox, and drag them into the event area:

undefined
Search for an action, and drag it into the Event Area.

If you’re using GML Code, simply write your code into the event window.

How to Add Motion

Okay, so, we need to move the ship.

In your Step event, add the following code/actions:

if keyboard_check(vk_up)
{
        motion_add(image_angle, 0.1);
}

undefined

Here we’re checking if the up arrow key is held down.

If you're holding the up arrow key, this adds motion to the instance, so it moves in a particular direction.

In GML Visual, the second action is “attached” to the first action. The second action will only run if the first action’s condition is true.

undefined

To attach “Add Motion” to “If Key Down”, drop it on the right edge of the conditional action, as shown above.

You can only attach actions to green "conditional" actions.

So – we’re adding motion in a direction. What direction is that?

That direction is the “image_angle” of the instance, which is where the ship is facing.

The amount of motion we’re adding is 0.1. You can change this to make your ship faster or slower.

Okay what now?

Run the game (press F5, or hit the Play button at the top) and in the game, press the up arrow key.

undefined

The ship is alive! It moves to the right, as that’s the default angle of an instance.

It’s not turning though…

How to Rotate an Instance

To move the ship, we’re adding motion towards the “image_angle”. This variable stores the angle of the instance’s rotation.

To rotate the instance, you simply need to change this variable.

In the same “Step” event, add this:

if keyboard_check(vk_left)
{
        image_angle += 4;
}
if keyboard_check(vk_right)
{
        image_angle -= 4;
}

undefined

The logic here is simple:

  1. If the left arrow key is held, subtract 4 from image_angle
  2. If the right arrow key is held, add 4 to image_angle

Run the game, and you can now move and turn!

undefined

This is great, but there is a small problem.

If your ship goes out of the room, it’s lost forever.

To solve this, we’ll make the ship “wrap” around the room: if it leaves through the top, it comes back through the bottom.

How to Wrap an Instance in GameMaker

In the same “Step” event, add this:

move_wrap(true, true, 0)

undefined

Make sure to add it outside of any conditions.

This tells the ship to wrap around the room when it’s outside. Both horizontal and vertical wrapping are enabled, and the wrap margin is set to 0.

The wrap margin controls how far outside the room the instance has to go before it wraps. We’re not using it for now, but it will come in handy later.

undefined

Aaand the ship movement is done! You can now move, turn and wrap around the room.

[ 1 Ship Movement 🥳 / 2 Destroying Rocks / 3 Finish Your Game ]

That’s one step off our checklist. To the rocks: we’re coming!

How to Shoot in GameMaker

Earlier we created an object called obj_bullet. To shoot, we’ll create a new instance of this object at the ship’s location.

undefined

The bullet will move at a fast pace, in the same direction as the ship itself.

When the bullet is outside the room, we’ll destroy it. This prevents a memory leak that would happen if all the bullets you shot continued to exist forever.

How to Create an Instance

In the Step event of obj_player, add this:

if mouse_check_button_pressed(mb_left)
{
        instance_create_layer(x, y, "Instances", obj_bullet)
}

undefined

This checks if the left mouse button is “pressed”. This is different from checking if it’s “held down”, as this only checks if you’ve just hit the button.

If you hit the left mouse button, it creates an instance of obj_bullet. Apart from the object to create, it takes three other parameters:

  1. x: The x (horizontal) position where the instance will be created
  2. y: The y (vertical) position where the instance will be created
  3. layer: The room layer where the instance will be created

For the x and y, we’re passing in the x and y variables of the player, so the bullet is created at the same position. We’re setting the layer to “Instances”.

undefined

You can now shoot! Thing is… the bullets don’t move at all.

How to Move an Instance Constantly

For the bullet, we’ll set its speed once it’s created. After that, it will continue to move forever until it’s outside the room.

undefined

Double-click on obj_bullet. In the Events window, add the “Create” event.

This event is the first to run in an instance, and only runs once. That’s why it’s called “Create” because it runs as soon as the instance is created.

In this event, add this:

speed = 10;
direction = obj_player.image_angle;

undefined

We’re telling the bullet to move at a speed of 10 – that’s 10 pixels every frame. Change this to make your bullet go faster or slower.

So that’s how fast your bullet moves, but where does it move?

That’s what direction controls. We’re setting it to obj_player.image_angle – which means we’re pulling image_angle from obj_player – telling the bullet to move where the player is facing.

How to Destroy an Instance in GameMaker

Our bullets should be moving now, but as I said before, they should be destroyed when they exit the room.

undefined

In the Events window, click on “Add Event”. Hover over “Other” and select “Outside Room”.

This event runs as soon as the instance has exited the room area. Add this here:

instance_destroy();

undefined

I think this explains itself… Here, the instance is destroyed, so it no longer exists in the room.

Of course, the object itself continues to exist in the Asset Browser, and new instances can be created from it at any time.

undefined

Woohoo! We can now shoot.

Doesn’t look like the rocks care, though.

They better run.

How to Move in a Random Direction

All rocks should move in random directions, but at a slow speed, so they’re not too hard to catch.

undefined

Double-click on obj_rock. Add the Create event, and add this there:

speed = 1;
direction = random(360);
image_angle = random(360);

undefined

First we’re setting the speed to 1. This is very low compared to the bullet’s speed of 10, which is expected.

Then we’re setting the direction to random(360). This can be any random number from 0 to 360 (a full circle).

That sets the direction where the rock moves, but doesn’t rotate the sprite – so we also apply a random number to image_angle.

undefined

The rocks are now moving! But there are two problems:

  1. If a rock goes outside the room, it will be lost and never come back
  2. The rocks look very still and boring

Rock Wrapping

undefined

In the same obj_rock object, add the Step event, and add this there:

move_wrap(true, true, 100);

image_angle += 1;

undefined

We enable wrapping for the rock, with a margin of 100. This means a rock will only wrap around once it’s more than 100 pixels outside the room.

If you had used a margin of 0, you'd see the rock jump from one point to another on-screen, but now it does that off-screen.

Finally, we’re adding 1 to the image_angle, so the rock continues to rotate constantly. It just looks more realistic.

undefined

Now rocks also wrap around the room, and they rotate, giving the game a more space-y feeling.

How to Destroy Rocks

It’s the battle we’ve been waiting for: Bullet vs Rock!

When they collide, we want to destroy both the bullet and the rock.

undefined

By now, you’re probably aware that an instance can be destroyed with instance_destroy() (or “Destroy Instance”). But that’s not all.

When a rock is destroyed, it should:

  1. Create a particle effect
  2. If it’s a big rock, become a small rock
  3. If it’s a small rock, “reincarnate” as a big rock

This way, the game never runs out of rocks: when you destroy a small rock, it becomes a big rock, and is placed off-screen so it can enter the room again.

How to Collide in GameMaker

When one instance touches another, it’s called a “collision”.

Let’s program the collision between a bullet and a rock. We’ll do it from the perspective of the rock, as that's the object that will be affected the most.

This means we’re working in obj_rock, not the bullet object.

undefined

Open obj_rock. Click on “Add Event”, go under “Collision”, and select obj_bullet.

This event will run when the rock collides with a bullet.

Add this here:

instance_destroy(other);
effect_create_above(ef_explosion, x, y, 1, c_white);

direction = random(360);

undefined

Add these actions, and apply “Destroy Instance” to “Other”.

This does four things:

  1. It destroys the “other” instance, which is the bullet. GameMaker gives you the other variable in a collision event, so you can modify the instance you collided with.
  2. In GML Visual, use the drop-down arrow to assign this action to the “Other” instance, so the bullet is destroyed.
  3. It creates an explosion effect at the rock’s location. Its size is medium (1) and its colour is white.
  4. It sets the direction to a random value. When the rock eventually becomes a small rock, or respawns, it will move in a new direction.

undefined

The event isn’t finished yet, but you can see our logic working. You can shoot at a rock and change its direction. A particle effect is also created.

How to Use Comparison Conditions

We’ll now program a big rock to change into a small rock, and a small rock to respawn.

To control the number of rocks in the room, we’ll only respawn a rock if there are less than 12 rocks in the room. This will be done using a “comparison condition”.

We want to use conditions to ask questions, and do this:

undefined

In the same collision event, add this:

if sprite_index == spr_rock_big
{
        sprite_index = spr_rock_small;
        instance_copy(true);
}
else if instance_number(obj_rock) < 12
{
        sprite_index = spr_rock_big;
        x = -100;
}
else
{
        instance_destroy();
}

undefined
Highlighted: Pay attention to the conditions.

That’s a lot of stuff, so let’s break it down block-by-block.

  1. The first block checks if the rock is big, by checking its sprite.

    If it’s big, it’s changed into a small rock, and the instance is then copied so we get two small rocks.

  2. The second block starts with “else”, so it only runs if the preceding condition is false – meaning the rock is small.

    It then checks if there are less than 12 rocks in the room, and if that's true, it changes the rock into a big rock.

    1. It also sets the rock's x (horizontal) position to -100 so the rock goes outside the room and can re-enter.

  3. The final block only runs if the both preceding conditions are false, meaning the rock is small and there are already 12 or more rocks in the room.

    In that case, the rock is destroyed.

Now run the game, and FIRE!

undefined

You can now destroy rocks, which respawn, resulting in infinite gameplay.

[ 1 Ship Movement 🥳 / 2 Destroying Rocks 🥳🥳 / 3 Finish Your Game ]

One final task to go!

How to Finish Your Game Loop

Move and shoot all you want, there’s no point in playing unless there’s great danger.

When your ship runs into a rock, it should explode immediately, and the game should restart after two seconds.

To restart the game after two seconds of the player losing, we’ll use “Alarms”.

How to Use Alarms in GameMaker

undefined

Go to obj_player, and add a Collision event with obj_rock.

In this event, let’s program what happens when the player collides with a rock:

effect_create_above(ef_firework, x, y, 1, c_white);
instance_destroy();
obj_game.alarm[0] = 120;

undefined

Add the actions, and apply “Set Alarm Countdown” to “obj_game

Here we’re doing three things:

  1. Creating a “firework” effect, with a medium size and white colour
  2. Destroying the player instance
  3. Setting Alarm 0 in obj_game to 120

Wait… “Setting Alarm 0 in obj_game to 120” – what does that even mean?

How Do Alarms Work?

You know how you set an alarm for 6AM, and you then go to sleep? The alarm goes off at precisely 6AM in the morning.

GameMaker also has alarms. You can tell an Alarm event to run after a number of frames. After that number of frames have passed, that event will run.

In the code above, we’re telling obj_game to run its first alarm (Alarm 0) after 120 frames (two seconds). In that event, we’ll restart the room.

Why didn’t we create the alarm in the player object?

Because we’re destroying the player instance. You can’t run alarms in an instance that doesn’t exist.

How to Restart the Room

undefined

Open obj_game. Click on “Add Event”, and add the “Alarm 0” event.

In that event, add this:

room_restart();

undefined

This will simply restart the room, so you can play again.

This is almost done – but for obj_game to work, it has to be in our room. Right now it’s not!

undefined

Open Room1 from the Asset Browser. Select the “Instances” layer, and from the Asset Browser, drag obj_game into the room.

Since it doesn’t have a sprite, it’ll appear with a question mark. You can place it anywhere – its location doesn’t matter, only that it exists.

undefined

In the game, you can now hit a rock and lose! Two seconds after that and you can play again.

[ 1 Ship Movement 🥳 / 2 Destroying Rocks 🥳🥳 / 3 Finish Your Game ]

We’re almost done…

How to Add Score in GameMaker

You have a great playable game now. But how will you show your friends how good you are without a score counter?

We’ll create our own variable to store the score. That variable will appear on-screen. When a rock is destroyed, we’ll add 50 to that variable, increasing the player’s score.

undefined

Open obj_game, and add the Create event. Add this there:

points = 0;

undefined

We’ve created a variable called “points” and set its value to 0.

Before we program how the score changes, let’s draw it to the HUD.

undefined

Add the “Draw GUI” event to the obj_game object. Add this there:

draw_text(10, 10, points);

undefined

The “Draw GUI” event runs every frame. Here you can draw anything to the screen, and it will appear above the game, acting as HUD.

We’re drawing the points value at 10, 10 on the HUD. You’ll see it if you run the game:

undefined

It’s stuck at 0 though. Let’s make it increase when you destroy a rock.

undefined

Open obj_rock, and open its existing Collision event with obj_bullet.

Add this there, outside of any conditions:

obj_game.points += 50;

undefined

I’ve added the action at the top of the event

Here we’re adding 50 to the points variable in obj_game.

We created the points variable in obj_game, but we’re trying to modify it in the obj_rock object – so we have to address the owner of the variable first. That’s why we write “obj_game.points”.

undefined

Run the game, and you will see your score go up as you shoot away at rocks!

And with that:

[ 1 Ship Movement 🥳 / 2 Destroying Rocks 🥳🥳 / 3 Finish Your Game 🥳🥳🥳 ]

Your game is finished!

What’s next? Well, you've got plenty of choice:

Share your game for free on GX.games.

Tip: Did you use GML Visual to make your game? Try it with GML Code now.

You will get a better understanding of GML having used both Code and Visual.

Happy GameMaking!