The Scrolling Shoot`em Up, or Shmup, is a classic

GameMaker Shoot’em Up
The Scrolling Shoot’em Up, or Shmup, is a classic and well-loved game genre that has spawned
countless classic games and a multitude of sub-genres. Although it is less popular today than during
the golden years it enjoyed in the 90s, it is still a useful exercise in game creation, with functionality
including input response, object creation, time control, and spatial logic.
Basic Starter File
Start by downloading the starter file from Moodle. This includes a basic set of sprites, a player object,
and a room for the first level. The sprites are from one of the classic 1980s shmups, Gradius.
The Room
Examine the settings in rmLevel01 – the room has been set to 320 x 240, however if you look at
the ‘view’ settings, you will see that ‘port on screen’ has been set to 640 x 480. This allows us to use
pixel style graphics and show the game at double size on the screen. To make this work, you need to
tick the option to ‘enable the use of views’. These settings will be more useful later on when we add
scrolling to games.
Objects
The player object has been created for you. Create the rest of the objects as follows:




obBullet – use spPlayerBullet
obEnemy – use spEnemy
obPowerUp – use spPowerUp
obControl – no sprite
Animation
Some of the sprites included in the file are animated. GameMaker defaults to showing animations at
one frame per step. This may be too fast, so you might want to modify the speed. Try it with the
player object like so:

obPlayer – Create Event: set the animation speed
image_speed = 0.5;
This will set the animation to half speed, i.e. one frame every two steps. Adjust as needed. Add this
code to any other animated object if you think that that animation is too fast.
Player Movement
The player ship will be controlled using the keyboard, moving the ship around the play field but
keeping it within the boundaries of the viewport. This will be basic, pixel-by-pixel movement. We will
not use physics based motion like we did with the breakout clone, because the movement in a
Shmup needs to be more finely controlled.
1. obPlayer – Create Event: make a moveSpeed variable, to make it easier to modify the
movement speed of the player, otherwise we will need to edit it for every key.
moveSpeed = 4;
2. obPlayer – Keyboard Event (Right): move the player to the right, if possible. Keep the player
within 32 pixels of the edge of the screen. Use room_width so that we can change this later
if needed.
x += moveSpeed;
if (x > room_width – 32) {
x = room_width – 32;
}
3. obPlayer – Keyboard Event (Left): do the reverse for the left key:
x -= moveSpeed;
if (x < 32) {
x = 32;
}
4. Repeat the above for the up/down keys, using ‘y’ and ‘room_height’ instead.
Test it now – You should be able to move your ship around using the arrow keys
Note: There is a major flaw in this movement system. By pressing moving vertically and horizontally
at the same time, you can actually move at a faster rate. In a production game this would be
unacceptable, however at this stage it is not a major concern. We can solve this problem later on.
Shooting Bullets
We will use a variable with local scope to temporarily hold the bullet as we create it. This allows us
to modify the bullet, changing its speed and direction as needed. After the function has finished, the
variable is forgotten, which is good for memory management.
1. obPlayer – Keyboard Event (Z): create a bullet and start it moving.
var b;
b = instance_create(x, y, obBullet);
b.direction = 0;
b.speed = 10;
The code ‘instance_create’ will spawn an instance of an object at the given coordinates, in
this case the x/y position of the player ship. The variable ‘b’ holds the newly created bullet
instance while we modify its direction and speed.
Note: If you test this now you might notice a problem – the bullets come out in a continuous stream,
making it far too easy to kill the enemy ships. Let’s add a delay between each bullet.
2. obPlayer – Create Event: add variables to stop automatically shooting, and give a small
delay between each shot. The variable ‘canShoot’ is a Boolean, and is used to stop the
bullets from firing. The ‘coolDown’ variable determines how long the delay will be.
canShoot = true;
coolDown = 10;
3. Go back to the Z key event and wrap an if statement around the bullet creation code:
if (canShoot == true) {
// original code as above
canShoot = false;
alarm[0] = coolDown;
}
In this code, we first check if we are able to shoot. If we can, we fire the bullet, then set
canShoot to false to prevent firing again until the weapon has cooled down. Then we engage
an alarm and set it to the coolDown period. Alarms tip down at one increment per step, so in
this case the alarm event will be triggered after 10 steps.
4. obPlayer – Alarm [0] Event: when the timer runs out, reset the canShoot variable:
canShoot = true;
Test it now – You should be able to fire bullets
Spawning Enemies
Every good Shmup needs waves of enemy ships to challenge the player. GameMaker features a
timeline system that makes it very easy to create this effect. We can create a timeline for each level
in the game, allowing us to create multiple levels of varying difficulty.
1. Create a new timeline by clicking on the hourglass. Call it ‘tlLevel01’.
2. Timelines work using moments, counted by steps.
Every step of the game engine will count up towards
the next moment on the timeline. Initially, we will
create two moments, at 60 and 120 steps. We will
add actions to these moments to create instances of
enemies using an execute code block as we would
with an object. You can add as many moments as you
need in your level.
3. Add code to each moment to create enemies and start them moving, using the same style of
code that we used for the bullets. In this example, we use the room_width and room_height
variables to place the enemy off the right hand side of the screen:
var e;
e = instance_create(room_width + 32, room_height/2, obEnemy);
e.speed = 3;
e.direction = 180;
4. The timeline needs to be attached to an object so that the game can execute the commands.
Create a new object called ‘obControl’. Add the following code to the create event:
timeline_index = tlLevel01;
timeline_running = true;
timeline_loop = true; // optional, useful for testing
This links the timeline to obControl, then starts running it. An instance of an object can
only have one timeline at a time. Insert obControl into the room in the same way that we
created the HUD in the previous tutorial.
Test it now – You should see the enemies flying onto the screen based on the timeline
Extension: sometimes enemies in Shmups move along predetermined paths to make them more
difficult to shoot and to avoid. GameMaker features a path system that allows you to plan motion
paths and attach them to objects. Look up paths in the help files (?) and try to find out how to make
your enemies fly along a wavy path.
Damaging Enemies
We need to make something happen when our bullets hit the enemy ships. It would be easy to
simply destroy the enemies in the same way we broke the bricks in the previous tutorial. However, a
more sophisticated solution would be to give the enemies some amour, so that we need to shoot
them more than once.
1. obEnemy – Create Event: We’ll start by giving the enemy an armour variable, so that it takes
more than a single hit to destroy it. Later on, we can make more types of enemies with their
own properties, such as armour and selective shielding.
armour = 2;
2. obBullet – Collision with obEnemy: Next, we reduce the amour when a bullet collides with
the enemy. We use the ‘with’ block here, to redirect the code from the bullet to the enemy.
After reducing the armour, we check if the armour has been depleted, and if it has we
destroy the enemy. At this point, you could also add scoring, or create explosions and other
eye candy.
with(other) {
armour -= 1;
if (armour <= 0) {
instance_destroy();
// add scoring code as required
}
}
3. obBullet – Collision with obEnemy (continued): After hitting the enemy, we need to destroy
the bullet, otherwise it will keep on going forever. Put this function after the code above:
instance_destroy();
We can modify this system later on to allow energy levels in the weapons. For example, a basic
bullet might have an energy level of 1, but you could upgrade it to 2 and destroy the basic enemies
with a single hit.
Test it now – You should be able to shoot and kill the enemies
Taking Damage
The next thing to do is to allow the enemies to damage the player. The best place to do this is in the
player object – have the player check for collisions with the enemies, rather than have every single
enemy checking for collisions with a single player object. Since this has the look of an old school
shooter, let’s make it a single hit kill. If you want, you can try to extend it later with a health system.
1. obPlayer – Collision with obEnemy: Cause damage to the enemy, destroy it if necessary
with(other) {
armour -= 10;
if (armour <= 0) {
instance_destroy();
}
}
2. Also in the same event: reduce the lives and check lose conditions. Use similar code to the
systems you built in the breakout tutorial.
lives -= 1;
if (lives > 0) {
// reset player (think about the ball in breakout)
} else {
// game over – do whatever you want to do (restart, change room)
}
3. obControl – Create Event: set up the lives at the start of the game
lives = 3;
There is plenty of scope for extending this system. You could make the ship temporarily invincible
using alarms, or make it drop its power-ups before it respawns, giving the player the option to regain
their strength.
Test it now – Try crashing into the enemies
Power-ups
We want to be able to upgrade our guns, so that we can cope better when the action starts to
intensify. We’ll do this by making the enemy drop a power up item at random.
1. obEnemy – Destroy Event: a one in ten chance to create a power-up object, moving left
if (irandom(10) == 0) {
var p;
p = instance_create(x, y, obPowerUp);
p.direction = 180;
p.speed = 1;
}
The function irandom(n) returns a random integer (whole number) between x and n. We use
this to give a one in ten chance of something happening. If it comes out as true, we then
create an instance of the power-up and start moving it slowly to the left.
2. obPlayer – Create Event: add a weapon variable to keep track of our weapon state, and
another variable to establish the maximum upgrade level.
curWeapon = 1;
maxWeapon = 2; // change this to the amount of possible upgrades
3. obPlayer – Collision with obPowerUp: upgrade weapon state, destroy power-up
if (curWeapon < maxWeapon) { curWeapon +=1; }
with (other) { instance_destroy(); }
4. obPlayer – Keyboard Event (Z): enhanced weapons, based on curWeapon value. This
function has changed significantly, with the addition of an if/else statement. If the current
weapon is ‘2’, we fire two bullets together.
var b;
if (canShoot == true) {
if (curWeapon == 1) {
b = instance_create(x, y, obBullet);
b.direction = 0;
b.speed = 10;
} else if (curWeapon == 2) {
b = instance_create(x, y-2, obBullet);
b.direction = 0;
b.speed = 10;
b = instance_create(x, y+2, obBullet);
b.direction = 0;
b.speed = 10;
} else {
// add code for more weapons as above (change maxWeapons)
}
canShoot = false;
alarm[0] = coolDown;
}
Enhancements





Paths – you could make the enemies fly along a path, rather than in a straight line.
GameMaker features a path system – you can design paths, then tell the enemy to move
along it when you create it in the timeline. Search the GM help files to find out how.
Different Enemies – create more enemy types with different properties and behaviours.
More Weapons – add further upgrades to the weapon systems.
Eye Candy – make explosions to display when an enemy is destroyed.
Good coding practice: this time, when you test, hit the red play button (debug). In the debug
info window, select Tools >> Show instances. This will show you how many instances of each
object there are in the game. Observe what happens when you fire your bullets. The amount
of instances will keep rising, because your bullets keep going after they leave the screen.
This is bad, because eventually you will run out of memory. The solution is to destroy the
bullets when they leave the screen (remember the ball from breakout?).