[GMS-S] Creating A Simple Shooter Game Like 1945

Once you have GameMaker: Studio set up and ready, it would be a shame not to make a quick game and test that everything works correctly, so let's go ahead and do that now, learning a little about how GameMaker: Studio works along the way.

The game we are going to make to test and learn about GameMaker: Studio will be a simple top down shooter in the 1945 style, so in GameMaker, let's start by adding in a couple of sprites and by creating an initial “menu” room for the player when the game starts.

Adding A Sprite

Sprites are small images that can be animated and displayed in your game, and they can be added either from the IDE buttons at the top, or by right-clicking the sprite resource folder in the resource tree on the left and selecting “Add Sprite”.

This will bring up the Sprite Properties Editor window, where you can now click the “Load Sprite” button and browse to the folder where you unpacked the resources ZIP previously. You will need the image named “sprTitle1945”, so select it and load it into the editor. You can name the sprite – making it easier to know what you are doing in the game code when the games get more complex – so call it “sprTitle1945” too.

You should set the origin of the sprite to the center (there's a button for that), as that'll make it easier to position within the game room – the origin is simply the point that will be used to “pin” the sprite to an instance of an object. With that done you can close the current sprite properties editor and add another new sprite to the resource tree.

Call this sprite “sprButtonPlay1945” and then add the image with the same name from the resource pack you downloaded. Set the origin to the center, as before, and then close the editor window.

Backgrounds

Apart from sprites, you can also have backgrounds in GameMaker: Studio. These are further graphic resources that are used for tiling and creating static background images in your game, and we need to create one for the game rooms in our shooter game. You can create a new one easily by right clicking on the resource tree or using the “add background” button of the IDE to open up the Background Properties Editor.

Call this new background resource “bckSeaTile”, as we will be using it to give a sea background to our game, and then click the Load Background button and browse to the image of the same name. Once you have loaded this image, you can close the background properties editor as we won't be doing anything else with this image.

Objects

We now need to create two objects for our game. One to display the title image and one to act as a button to let the player start the game. Objects are like blueprints for instances that will appear in your game. You can only have one object type, but you can use it to create multiple instances in a game room. Objects are what we use to draw things to the screen and to create the game characters as well as for controlling what happens in the game.

You can create a new object the same way as you can a sprite or a background (right mouse button on the object resource or use the button at the top), so do that now and call it “objTitle”. We want to assign a sprite to this object as it will be used to display the title when the game starts, so click on the “menu” button – highlighted in the image below – and select the 1945 logo sprite we added at the start.

We don't require this object to do anything else so you can click the “OK” button to close the window.

The next object we'll make is the “Play” button for the player to start again so make another object resource now, and give it the “Play” sprite we added and call it “objButtonPlay”. This object needs to respond to a mouse click, so we need to add a Mouse Button Event. Events are specific moments in a game where something happens and you can add code or Drag And Drop actions to deal with it. In this case we will use code and the Mouse Left Pressed Event to detect when the mouse has been clicked on the object, so add this event now by clicking the Add Event button in the object properties.

Here we are going to add a line of code go to to the main game room, so drag a code action (from the Control actions tab on the right) and add:

room_goto(rmGame);

You can close the code editor now and the object editor too, and we'll add some rooms to our game...

Rooms

Everything that happens in your game will happen in a room. Rooms in GameMaker: Studio are used to split the game into discreet areas for different purposes, like you can have a menu room, and then a game room and then a pause room, etc... and every game needs at least one room to run. In our mini-game, we want two rooms, one for the titles and play button, and the other for the game itself.

We'll start by making the basic title room, so right-click the room resource folder and select “Create Room”. This will open the room editor where we can set the initial state of a room. Here we want to assign a background, so go to the Backgrounds tab and then select “Background0” and use the “menu” button to select the sea background we added previously:

You need to make sure that you have ticked “Tile Vert.” and “Tile Hor.” so that the background tiles across and down the whole room, and you should also set the “Vert Speed” to 2, as this will give the background a vertical scroll down the screen of 2 pixels per step. This way we can use it to create the illusion of an upwards movement.

You can now go to the Objects tab, and from here we can add in an instance of our Title object and an instance of our Play object, as shown in the image below:

Our final task for this room is to set the room name in the Settings tab, so click that and change the room name to “rmMenu”. We don't need to set anything else here as the default values are perfectly fine for what we want. You can close this room now and we'll use it to create the main game room, since it will have the exact same properties as the menu room.

To create the game room, right click on the room “rmMenu”, and then select “Duplicate Room”. This will create a new room resource that is exactly the same as the one being duplicated. In the Settings tab, change the room name to “rmGame”, and then go to the object tab and delete the two instances that are there, since we don't need the title or the play button in the game room. We'll add in more instances later, but first we need to create the objects. We'll do that now, so you can close the room editor.

Game Control

If you decided to test your game just now, you could and you'd have a title screen and a clickable button that will take you to the (empty) game room. That's not much fun, so lets make some objects to liven things up a bit!

Create a new object and call it “objControl”. As the name implies, this will be used to control some of the general aspects of the game – things like score, or creating enemies. Now add a Create Event to the object and give it a code action with the following:

score  = 0;
lives  = 3;
health = 100;
alarm[0] = room_speed;
alarm[1] = room_speed * 2;

What we are doing here is setting three built in global scope variables to some default values for the start of the game (health, lives and score), then we are setting two Alarm Events to run later. An alarm event is an event that you can add code too and it will only be called when the alarm value reaches 0. In this case, we are going to have one alarm that spawn islands as a nice visual effect, and the other alarm will spawn the enemy.

Add an Alarm[0] event now, and give it a code action with the following:

var xpos = irandom(room_width);
instance_create(xpos, -100, objIsland);
alarm[0] = room_speed + random(room_speed * 4); 

This code will create an instance of the island object (which we will add when we are finished with the controller) to a random position along the x axis and at -100 on the y axis. This will spawn it outside of the visible room area – as the room coordinates are (0, 0) for the top left and (1024, 768) for the bottom right – and we'll have it move into view and scroll down the screen to add to the effect of movement over a surface for the player. The final line resets the alarm again to a value between 1 and 5 seconds, ready to spawn another island.

You can add an Alarm[1] event now too, and we'll use a similar code block to spawn the enemies:

var xpos = irandom_range(50, room_width-50);
instance_create(xpos, -100, objEnemy);
alarm[1] = room_speed * 2;

As you can see, this is similar to the previous code, only now we limit the random initial x axis position to prevent the enemy spawning at the very edges of the play area, and we reset the alarm to a fixed 2 seconds. 

Drawing

All objects in your game have a Draw Event. You may not have added one to the object, but it's there as GameMaker: Studio will “default draw” any object that has a sprite assigned to it, but you can also add different draw events to create HUD's and overlays or to change the default drawing behavior. For our controller, we haven't assigned it a sprite, so nothing will be drawn by default, but we do want it to draw a basic HUD to keep the player informed of their progress through the game, and for that we will use the Draw GUI event.

This event is for drawing on the GUI Layer, which is essentially an onion skin layer used for drawing overlays and HUDs on the main game window. The regular draw events will draw things based on their relative position within the game room, while the GUI event will be drawing things at a fixed position within the game window, so it is ideal for displaying the score or any other information to the user.

In this case, we are going to use it to draw the players lives, the players score and the players health, so add add a Draw GUI Event now with this code:

draw_set_color(c_white);
draw_set_font(fntImpact);
draw_text(20, 20, string(score));

var ww = display_get_gui_width();
var hh = display_get_gui_height();
for (var n = 0; n < lives; n++){
draw_sprite(sprLife1945, 0, 24 + (n * 80), display_get_gui_height() - 75);
}

draw_healthbar((ww/2) - 128,  hh - 48, (ww / 2) + 128, hh - 24, health, c_black, c_ltgray, c_ltgray, 0, true, true);

This code sets a couple of the basic draw parameters for text (more on fonts in a moment), then draws the score to the screen in the top left corner. Next we use a loop to draw the number of lives that the player has to the bottom left, and finally we draw a healthbar for the player in the middle of the display. Note that we use a new sprite here called “sprLife1945”, so you will need to add this now from the resource pack otherwise you’ll get errors later.

With that done, we can close the controller object as we are done with it for now, but don't run the game yet! Or do, if you want to see what errors look like, as we have used some resource names that haven't actually been defined yet, meaning that the game will not compile...

Fonts

In most games you'll want to display text on the screen at some point, and for that you'll need a font resource. You can add any font on your system to your game – although you should make sure that you have appropriate licences if it's not one of the default fonts – and it will be transformed into a texture when your game is compiled so it works on any platform. To add a font, right click on the Font resource folder and select “Create Font”, then in the font properties window, browse to the font called “Impact” (installed by default on Windows) and set it's size to 24 points, and set the name of the resource to “fntImpact”:

You can close this window now and your controller object will use this font to draw the score to the screen.

The Player

We're nearly done with our mini-game, believe it or not, and all we need to do now are add in the Player, the enemies and the islands. We'll add the player now, so make a new object and call it “objPlayer”, then click the “New” button under the sprite menu to create a new sprite for it. Call the sprite “sprPlayer” and then browse to the resource pack and select “sprPlayer_strip2”. This sprite is made up of two sub-images and GameMaker: Studio will parse the “_strip2” of the sprite file name to automatically create these from the single image.

Close the sprite properties (assigning the sprite to the instance) and now add a Step Event to the player object with the following code:

if keyboard_check(vk_up) y -= 4;
if keyboard_check(vk_down) y += 4;
if keyboard_check(vk_left) x -= 4;
if keyboard_check(vk_right) x += 4;

x = median(80, x, room_width-80);
y = median(80, y, room_height-120);

if (keyboard_check(ord("X"))){
if (alarm[0] < 0) {
    alarm[0] = room_speed * 0.25; 
    instance_create(x-30, y, objPlayerBullet);
    instance_create(x+30, y, objPlayerBullet);
    }
}

The Step Event, is an event that is run every game step, ie: if the room speed is set to 30, then you would get 30 steps in a second. This code does two things:

  • First it checks the arrow keys to see if they have been pressed and adds 4 along the horizontal or vertical axis if true, with a couple of extra lines there to limit the player position and ensure that they remain in the playable area of the room.
  • Next it checks for the “X” key being pressed, and, if it is pressed, it checks to see if alarm[0] has counted down (and alarm is “off” when it is at -1) and if both those conditions are true, then it spawns a couple of bullet objects.

You can close this code window now and add in an Alarm[0] Event. We don't need to add any code here, but we do need to add a comment. Alarms can be used as timers but for them to be recognised they need to have an action added to them, so we simply add a code action with a comment like this:

/// Shoot Timer Event

This will cause the alarm to run when set and so it can be used as a timer in the game. Without this comment, our shoot code would not work correctly.

The final event that we'll add to our Player object for now is a Destroy Event. This will be triggered whenever the instance is destroyed (ie: removed form the room), and we'll use it to remove and check the lives with the following code:

if (--lives > 0) {
health = 100;
instance_create(x, y, objExplosion);
instance_create(room_width / 2, room_height - 200, objPlayer);
}
else{
room_goto(rmMenu);
}

You can now close the code action and the object properties as we need to add in other objects first before we can add the final events that the player requires.

Islands, Enemies And Bullets

Time to add in our “supporting cast” of objects for the game. To start with we'll create some islands... Create an object and call it “objIsland”, then add a sprite from the resource pack (as we did for the player). Now give it a Create Event with the following code:

image_speed  = 0;            // Don't animate
image_index  = choose(0, 1); // Randomly choose a sub-image
vspeed = 2;                  // Scroll this instance downwards

We also need to give it a Step Event to check and see if it's moved out the bottom of the screen, so add that now with this code:

if (y > room_height + 100) {
instance_destroy();
}

Close this object and create a new one now. This we'll call “objEnemy”, and you should add an appropriate sprite from the resource pack to it. It'll need a Create Event with this code:

vspeed = 3;                // Set the vertical speed
alarm[0] = room_speed * 1; // Set shooting timer to a second
hp = 2;                    // Set the “health” of the enemy

Note, we give the enemy a unique instance variable “hp” to control its health, since the built in “health” variable is global in scope and is being used by the Player object. Next we need an Alarm[0] event with the following for shooting:

instance_create(x, y, objEnemyBullet);
alarm[0] = room_speed * choose(1, 2, 3);

Then we need a Step Event to check if the instance leaves the room (like we did for the island):

if (y > room_height + 100) {
instance_destroy();
}   

That's it for our enemy for now, so you can close this object and create another new one. This will be for the player bullets, so call it “objPlayerBullet” and assign it a sprite. We only need this object to have a Create Event to set it's speed, so add that now with this line of code:

vspeed = -5;  // The instance will move up the screen

You can close this object and make one final new one for the enemy bullets. Call this one “objEnemyBullet” and give it the following code in its Create Event:

vspeed = 5;  // the instance will move down the screen

We will add one final object to make things a bit nicer... an explosion that will be shown when the Player or an enemy dies.

Create another new object, call it “objExplosion” and assign it the explosion sprite from the resource pack. We only need to add a single event for this object, an Animation End Event. This can be found in the Other event category, which contains a number of special one-time events you can use.

The animation end event will be triggered when the image index has reached the last sub-image value – for example, a ten image sprite would have its animation end event triggered when the sprite image_index value reaches 9 – and in this case we'll use it to destroy the instance, as that way the explosion will show and then remove itself from the game when it's finished the animation. So, add this event with the following code:

instance_destroy();

Our secondary objects are now complete with the exception of one thing. Collision events.

Collisions

Collisions in GameMaker: Studio are calculated from the mask of the object. In general this is set to the sprite being used, although you can set it independently. However, for this game, we don't need separate masks and we can just use those that are defined for the sprites.

Our first set of collisions will be in the Player object “objPlayer”, so open up the object properties for it and then click the Add Event button. Select the Collision Event, and then select the object we want to register a collision with – in this case it is a collision with the enemy bullet “objEnemyBullet”.

Now, when the two sprite masks for the objects overlap in the room, this event will be triggered. We need to add some code now to deal with this event, so add a code action with the following:

health -= 10;                    // Reduce health because of damage
if (health < 1){                 // If health has fallen too low
instance_destroy();              // Destroy the calling instance
}
with (other) instance_destroy(); // Destroy the bullet

Note that we use a special GameMaker “keyword” here – other. This keyword is used in the collision event to identify the “other” instance in the collision, which in this case would be the bullet. Using “other” to change scope in this way means that you can run code in the instance with the collision event or in the instance that is being collided with, like in this case.

Close the code action and add another Collision Event now for collisions with the object “objEnemy”, as we want the player to be penalised for colliding with an enemy plane too. In this event add the following code:

with (other){
instance_create(x, y, objExplosion); // Create an explosion at the enemy position
instance_destroy();                  // Destroy the enemy
}
instance_create(x, y, objExplosion); // Create an explosion at the player position
instance_destroy();                  // Destroy the player

We also need to add a collision event to the enemy object “objEnemy”, so open that now and add a collision event with the player bullet object “objPlayerBullet” with this code:

if (--hp < 1) {                      // Check if the hp variable is less than 1
instance_create(x, y, objExplosion); // Create an explosion
instance_destroy();                  // Destroy the instance
score += 20;                         // Adds to the global score variable
}
with (other) instance_destroy();     // Destroys the bullet

Our mini game is pretty much complete now, and all that's left is to set up the game room and test it!

Testing And Debugging

You should now open up the Room Editor for the room “rmGame”. We need to add an instance of “objControl” and “objPlayer” into the room, so that when it starts the game will play correctly, so select these and add them into the room (note that the controller has no sprite and so will appear as a blue circle with a “?” symbol):

There are two primary ways to test your game now. The first is by clicking the green “Play” button at the top of the IDE, and the second is to click the orange Debug button. Clicking “play” will compile your game and deploy it to the target platform for testing, but it does nor provide any debug information. It is similar to installing a final executable, but only temporary. Clicking the Debug button, will also launch your game, but it will also launch the Debug Module which you can use to check performance or find any bugs in the code.

To test our game press the “Play” button at the top of the IDE making sure you have selected the Windows target. You have finished your game and hopefully have enough of a head start to go on and improve it, or start something new with confidence!

Have more questions? Submit a request

0 Comments

Article is closed for comments.
Powered by Zendesk