My First Arena Shooter | DnD


My First Arena Shooter | DnD

Introduction

This tutorial will take you through the process of creating a small game using GameMaker Studio 2. The tutorial itself is rather large and covers everything from the GameMaker Studio 2 user interface to creating game graphics and then getting them moving, as well as player interaction within a game, and much, much more. So, to keep things simple we have split it into the following sections:
  1. Movement
  2. Shooting
  3. Enemies
  4. Tiles And Views
  5. Scoring
  6. Sounds
  7. Title Screen
  8. Spawners

Each section is also accompanied by a short video that takes you through each of the steps outlined in text, and you can close GameMaker Studio 2 at any time in the progress of this tutorial (saving your project) and when you next load the project you will be taken to the place where you left off. If you wish to play around with what you have learned so far, we recommend that you save the project in its current state - so that you can continue from the same point later - then save it again with a different name and edit the renamed project so as not to lose or change anything that is important to future sections.

The videos that accompany each section can be found from the following links:

  1. Movement
  2. Shooting
  3. Enemies
  4. Tiles And Views
  5. Scoring
  6. Sounds
  7. Title Screen
  8. Spawners


Movement

Starting A New Project

This is the My First Arena Shooter | DND™ tutorial designed to get you started making your first game with GameMaker Studio 2. Throughout this tutorial we will build a small "arena shooter" - a top down action game with a player, some enemies and lots of bullets. The final game will look something like this:

Final Game Screenshot

We will be keeping the tutorial as simple as possible, with the idea being to give enough of an overview of how things work for you to get stuck in and making your own games as quick as possible.

We'll quickly give an overview of how you create a new project from scratch for the future to start with.


NOTE: If you close the accompanying video then you can get it back by clicking here

First you would open GameMaker Studio 2 , and then click on the New Project button shown on the main Start Page:

New Project Button

You will then be presented with two options:

  • New Drag and Drop™ Project
  • New GameMaker Language Project

Drag and Drop™ is the powerful visual scripting language that permits you to code a project using chained action blocks, while the GameMaker Language (GML) is the propriety scripting language that permits you to create games using the code editor. For this tutorial we are going to use Drag & Drop so you would click that button and then choose a project name to go with the game you want to make.

NOTE: If you have experience with programming or are a less "visual" person then you may prefer to use code instead of the visual scripting tools, so this tutorial is also available as a Code tutorial here

Once you have created and saved this initial blank project you will be presented with the GameMaker Studio 2 workspace...


The Workspace

The workspace is the name we give to the main area in the middle of the window where you will be doing the bulk of your work. There are different types of workspace too, but we'll cover that a bit more later. On the right of the workspace we have the Resource Tree, which lists all the different elements your project can use, like sprites, or objects, or rooms. We will explain what each resource type is as we come to it in the tutorial, but we won't be covering all of them.

The Main Workspace And Resource Tree

It's worth noting that the resource tree is considered to be docked to the side of the window, and it can be opened or closed using the dock buttons:

Open And Close Dockst

and it can also be moved to a different screen position and docked there (for example on the left):

Changing Dock Position

GameMaker Studio 2 is fully customisable, so you can change the colours and fonts, or even set window layouts and save them. That aspect of the program won't be discussed in this tutorial and we'll be using the default layout, but you can find more information on customisation in the manual (press ).


Sprites

We have our new project and an empty resource tree, so it's time to get started making our game. The aim of this tutorial is to simply get a "player" object onto the screen and moving around, and the first thing we are going to need for that is a Sprite. A sprite is an image that is combined with certain properties which is then used in the game to represent something. In this case we are going to make a sprite to represent our player.

Let's go ahead and create our first sprite resource. Simply click the right mouse button  on the Sprite resource and select Create:

Create A Sprite

This will open the Sprite Editor where we can add an image and set certain properties for the sprite:

The Sprite Editor

To start with, you need to name the sprite. This name will be the unique identifier for the sprite throughout your game and can be anything you wish, although we recommend that you use some kind of identifier prefix like "spr" or simply "s", as, when you get multiple resource types in your game code, it makes everything far easier to read. So with that in mind, call this sprite "spr_player".

We now need to add an image to the sprite to use as our player. For that we'll use the following image in this tutorial, but you can create your own if you want:

Player Sprite

You need to click on the button  to open the file explorer where you can browse for an appropriate image, which must be either PNG, GIF, or JPG format. This tutorial has created a TutorialResources folder for you within the project files, and when you open the file explorer to choose a sprite, it should open on that folder where you can find the sprites used in the "Images" sub-folder. If you have any issues, you can also find the images here.

You will get a warning saying that this action cannot be undone, which is fine since this is a new sprite and we aren't going to over-write anything, so click "Yes" to continue. The Sprite Editor will now look like this:

Adding An Image

The top part of the editor will show a single image, and the main window will have a larger preview. If you add in a sprite animation, the top part will show each individual frame and clicking on them would show that frame in the preview window below, but as we only have one image in the sprite it only shows that image.

Now that we've added an image, we need to set its origin. The origin is simply a point on the sprite that will be used to position it within our game room, and you can set it by either clicking   anywhere on the preview image to set the origin to the mouse position, or using the drop down menu to set a fixed position for it:

The Origin Menu

You can see that in the image we indicate Middle Center so select that as the position for the sprite origin. With that done, we are now ready to create an Object Resource which will use our sprite.


Objects and Instances


Objects will be used for almost everything in your game, from the Player, to the enemies, to the bullets and explosions, and you can define how they behave and react by giving them code. But, before creating our first object, let's quickly run over what an object is conceptually.

The idea behind an object is to create a kind of blueprint of behaviours that can then be used within a game. We think of it as a blueprint because in a game you don't actually have any objects, you have instances instead. Instances are copies of the initial object placed within the game room. So, objects are in the resource tree, and are then used to create the instances that populate our game room. This means that changing an instance's properties will not change the properties of the object it was made from, however changing an object will change all subsequent instances created from it.

We are going to go ahead and create an object now. This object will be for our player and is what will permit it to move and shoot in the game room. To create the object, right click   on the "Object" resource folder and select Create:

Create Object

This will create a new, blank, object for us and open the Object Editor:

Object Editor


The object editor will be opened within the same workspace as the sprite editor, and it may push the sprite editor out of the visible space. You can hold down the middle mouse button   and move the mouse to "pan" the workspace around and you can also use  /   + the mouse wheel   to zoom it in and out. When you have multiple resources open you can also use  /  +  to open the workspace switcher and select the editor that you want to see directly.

Now we have our object we need to name it, so we'll follow the same convention we outlined previously and use a prefix to define what kind of resource it is and give it the unique name "obj_player" to match the sprite "spr_player" that we made previously.

We can now associate the sprite to the object by selecting it from the list of available sprites. To do this, you will need to click the button that is currently labelled "No sprite" and select the sprite "spr_player" from the list of available resources:

Adding A Sprite

Associating an object with a sprite in this way means that when you place an instance of the object in the game room, this is what will be drawn and certain attributes of the sprite will be used by the instance. Let's go ahead and place an instance in the game room now...


Rooms

The only resource that is created for you by default when you create a new project is the Room Resource. This is because all games require at least one room to run, and so GameMaker Studio 2 makes this room for you. You can delete it, and you can edit it, and you can create further rooms using the right button   menu. In this case we will simply edit the default room "room0".

Default Room

To open it for editing you need to double-click  on it, which will open the Room Editor in its own workspace:

The Room Editor

Rooms can be used for just about anything. You can have a single room for every aspect of your game, like splash screen, main menu, introduction, level 1, 2, 3, etc... or you can have a single room and generate everything using code. Normally you'd have a mix of both things, with some rooms fulfilling multiple purposes (like one room for all your different menus) and other rooms for a single purpose, like an overworld room, or a level room.

With the Room Editor workspace open, you will see that most of the screen is taken up with a large black area with grid squares over it. This area is the actual room, which is currently a blank canvas on which you can place resources to create your game level.

Everything that goes into a room is placed on a layer (we'll discuss layers in more detail in further tutorials) so make sure the Instance Layer is selected in the layer properties window:

Layer Properties

Then you can simply drag an instance of the object "obj_player" into the room by clicking  on the object in the resource tree and dragging it into the room where you want it to appear:

Add Instance To Layer

We can actually run the "game" now as we have a room and an object so go ahead and click the Run Button   at the top left of the IDE. You'll see some text scroll up in the output window at the bottom of the window, and then the game will run:

Game Image

Exciting stuff! Well, not yet... but it will be when we make our player instance actually do something. Before continuing, we should give the room a name, as the default name isn't very descriptive so give a slow double click   on resource name and call the room "rm_game". Now let's add some code to the player object.

Events and Code

You can close the game window now (if you haven't already) and then double click  on the "obj_player" object in the resource tree. This will take us back to our main workspace and focus it on the object we want to edit.

You'll notice that our object has another window chained to it, the Event Editor. A game in GameMaker Studio 2 is simply a selection of code within events that are performed a number of times every second. This is called the "game loop" and a single game loop is called a game frame. The number of game frames in a second is what gives us our Frames per Second (FPS) value for the project. By default this is set to 30, meaning that our game will perform a game frame (loop through all the game code) 30 times every second and in each single frame of the game code you have Events. These events fall into two broad categories:

  • Those events that happen every single game loop - like the Step event or the Draw event
  • Those events that happen only when a certain criteria has been met - like the Keypress event or the Create event

You can see all the event categories by clicking  on the Add Event button:

The Event List

In the image above you will see that we have highlighted the "Step" category, and within that the general Step Event, as this is what want to add to our object. If you select it then you'll see the event added into the Event Editor window and a new window chained to it:

The DnD&trade Editor

The new window is the DnD™ Editor and is split into three parts:

  • On the left we have the action list - this gives a list overview of all the actions in the event
  • In the middle we have our action workspace - this is where you drop the actions that you want to perform and edit them
  • On the right we have the action toolbox - Here you can find all the Drag and Drop™ action blocks that you can use to create your games

The idea of Drag and Drop™ is simple - you select an action from the toolbox and drag then drop it onto the action workspace. Once in the workspace you edit the parameters that it requires, and then continue to Drag and Drop™ further actions to "chain" them to the previous one. Note that actions are added in a linear fashion, so each subsequent action that you add will be added after the previous. Let's see how that works in practice by adding an action...

As mentioned above, the Step Event is run each and every game loop, so anything we put in here will happen once per game frame (30 times in a second for a 30 FPS game, 60 for a 60fps game, etc...). In this case we are going to add an action to the event to make the player instance move right across the screen. We could use the movement actions for this, but to give you a better idea of how GameMaker Studio 2 does things we are going to set the built in variable "x" to move and use the action Assign Variable :

Drag and Drop™ Assign Variable

We want to set the value of "x" to 4 relative to its previous value, so we set the action to look like this:

Final Action

Note that now in the list view on the left of the editor, we have the action written as plain text:

List View

So what does this do then? All instances have some built-in variables, of which "x" and "y" are perhaps the most important as they set the position of the instance in the game room. In this case we are telling GameMaker Studio 2 to take the x position value and then add 4 to it. Note that if we hadn't flagged the "relative" check-box, then we would be setting x to 4 rather than adding to it, and if we'd used -4 instead of 4, then we would have been subtracting 4 from x.

If you now run the game again, you'll see the player instance move off to the right:

Basic Player Movement

We now have some movement, but it's not very much fun for anyone... let's now add some new code to the player to make it respond to the user pressing the arrow keys on the keyboard.


Movement

We want to now make the player instance move when the user presses the Arrow Keys on the keyboard. Currently we are adding 4 to the "x" value every game frame, so what we want to do is only add 4 if the keyboard right arrow is being pressed. For that we use the if key down  action which will evaluate to either true or false if the given key is being held down, and if it evaluates to true, then we will move the instance by 4. The action can be found in the Mouse and Keyboard section of the action toolbox and you should drag it into the action workspace above the Assign Variable action:

Add Keyboard Action

Note that when you drag it near the existing action an area will be highlighted indicating that it can be placed either above or below the action in the chain (in the image above we place it above), and once you drop it you will see that it is connected to the Assign Variable action like this:

Chained Actions

That square chain on the left means that the "if" action will be called and then the Assign Variable action, but that they are independent of each other. We want to change this so that the Assign Variable action will only be called if a key is pressed so now we need to drag it onto the right hand side of the if keyboard down action like this:

Move Action Into If

Now what we have is the "if" checking for a key and only if it returns true (the key is being held down) will it run the assign variable action. We only need to set the key that is being checked now, so change the "vk_space" value for "vk_right" (the "vk_" variables are special built-in constants that are used to signify different keyboard keys). It should all now look like this:

Completed Action Blocks

The conditional we are checking is the value returned by the function "keyboard_check" which returns true if the key (in this case the right arrow) is being held down and false otherwise. Note that the assign variable action is placed to the right to indicate that it is only being run if the conditional check is true, and that this is also reflected in the action list on the left, where the assign variable entry has been tabbed too.

Run your game again (press ) and this time the player instance should do nothing unless you press the right arrow key.

We can expand the current action list now to cover the remaining three directions of up, left and down. Now you could repeat the whole process and add each action, or you could do what we'll do now, which is to copy and paste the actions we have and then edit them. To copy multiple actions, first you have to select them by holding down  /  and then left clicking on each of the actions we want to copy. Now hold down  /  + C to copy them and then  /  + V to paste them. They will automatically be pasted after the previous actions, so you can go ahead and do this three times so that we have a total of four "if" checks:

All If Checks

You can now edit the actions so that you have:

  • if right arrow key down (vk_right): x + 4
  • if left arrow key down (vk_left): x - 4
  • if up arrow key down (vk_up): y - 4
  • if down arrow key down (vk_down): y + 4
Final Actions

As you can see, we subtract from x to go left this time, and we have also changed the last two conditionals to change the "y" position instead of the x position, where subtracting from "y" moves up, and adding to "y" moves down. In GameMaker Studio 2 the (0, 0) position is considered as the top left hand corner of your room and the horizontal axis is the x axis and vertical axis is the y axis:

Room Axis And Position

Run the game now (press ) and move the instance with the arrow keys:

Player Moving Example


Rotation

We are almost finished this tutorial, but there is one final thing we want to happen with our player instance... We need to make it rotate to always face the mouse while it is being moved around the screen. That way, the user can move with the keyboard and aim and shoot with the mouse. We'll leave the shooting for the next tutorial in the series and simply add the rotation for now.

For this, we are going to use another of the built-in variables that all objects have - the image_angle. This variable controls the angle of the sprite assigned to the instance, so setting it to anything other than 0 will rotate the sprite (and its associated collision mask) by the amount given. By default this is set to 0 for every instance in the room, but it can be changed at any time using the Set Instance Rotation action .

But what are we going to set the rotation too? We actually need to use a function to get the angle that we want to set the sprite to, and then we'll store the value it returns in a variable ready to set the rotation of the instance.

NOTE: It's important to note that most DnD™ actions will take functions and expressions too, not just values!

In this case we are going to use a function to get the direction from the player instance to the mouse pointer and set the image_angle to that. So first of all, still in the "obj_player" Step Event we need to declare a local (temporary) variable and add our function to it. For that we drag the action Declare Temp  from the "Common" action library, and add the function like this:

Declare Temp Variable

A local (temporary) variable is one that is only valid for the event that it is used in, so it's like a "use and throw away" variable - we only need to get the direction once in this step so there is no need to make it an instance or global variable. In this case we have named the variable "dir" and in future actions that will be what we use to refer to it. The function we will use is point_direction, which takes two positions within the room and returns the direction from the first position to the second in degrees from 0° to 360°. In this case we get the direction from the player position to the mouse position, which we get from the two global scope variables mouse_x and mouse_y (global scope variables are variables that do not "belong" to any instance, but instead belong to the whole game and as such all instances can change them and use them).

NOTE: In GameMaker Studio 2 angles are calculated anti-clockwise where 0° is to the right, 90° is up, 180° is to the left and 270° is down.

You can now add the Set Instance Rotation action  below (from the Instances action library), and set it to use the local variable "dir" to set the rotation of the image_angle:

Set Image Angle

If you run the game one more time now, you should see that the player instance moves around and that it turns to follow the mouse:

Final Movement Test


Summary

The first section of this tutorial is now complete, and you have the player moving around and you have their "ship" turning towards the mouse ready to start shooting! Before going any further though, let's just go over a few of the core concepts that you should take away with you from this section :

  • You were shown how to create a New Project

  • You were shown how to dock windows to the workspace, and how to move around the workspace with the mouse

  • You learned that sprites are image resources with some additional properties

  • You learned that objects are what makes a game function, and that they are "blueprints" for instances in the game room

  • You learned about the game loop and Events

  • You found out that you can only have a game if it has at least one room resource

  • You added some basic Drag and Drop™, and learned about variables and conditionals

  • You made a test project that does something!

Hopefully when you look at that list you can feel proud of yourself. You've come a long way from knowing nothing to creating something that is actually interactive - if not quite a game yet - and have learned the basics of how to use GameMaker Studio 2. In the next section we'll expand on what you've learned here by adding bullets and other world items into our Arena Shooter game.


Shooting

Bullets

This section picks up where the previous section left off. In the previous section , you created a sprite, assigned it to an object and placed an instance of that object in a room. You then made it move around with the arrow keys, and always rotate to point at the mouse position. That was a good start, but it still wasn't a game, so in this tutorial we're going to add a shooting mechanic to the project.

NOTE: If you close the accompanying video then you can get it back by clicking here

Obviously the first thing we are going to need is a new sprite to represent a bullet. We covered how to add a sprite in the first part of this tutorial, so we'll only briefly run through the procedure here:

  • Click the right mouse  on the Sprites resource folder
  • Select "Create" to create a new sprite
  • Name the sprite "spr_bullet"
  • Click  "Import" and choose a suitable sprite (remember, while following this tutorial the file explorer should take you to the TutorialResources folder automatically where you can find the sprites used in the "Images" sub-folder). If you have any issues, you can also find the images here.
  • Place the origin of the sprite

If you have used the sprite that we used for the tutorial, you should be placing the origin near the bullet image "head" (as shown in the image below), as that is the point that we want to rotate it around and "pin" it into the room with. If you have used your own sprite then click the image where you think would be best place to put the origin for the image.

Placing The Origin

The Bullet Object

As with the sprite, we talked about how to create objects in the previous tutorial, so we'll only quickly run down how to do it here:

  • Click the right mouse  on the Objects resource folder
  • Select "Create" to create a new object
  • Name the object "obj_bullet"
  • Click  where it says "No Sprite" and assign the sprite we just created

Our new object will have the Events window chained to it and ready for us to add some code into, but first we are going to go back to out player object and edit that a bit. So double click  on the object "obj_player" from the resource tree to open it in the current workspace if it's not open already.

Open the action editor in the Step Event (double click  the event if it's not open already). We are going to edit this now to dynamically create instances of the bullet object as the game is being played. Instance don't just get placed in the room editor, they can also be created (and destroyed) at runtime using certain actions, as we'll see.

In our Step Event action workspace, we need to add the following action at the end of the current list, if mouse down  (from the Mouse And Keyboard action library):

If Mouse Down Action

This action functions just like the if keyboard down action and performs a conditional check to see if the left mouse button is being held down (remember, "if" conditionals check for a true or a false return value) and the subsequent blocks we add will be within this conditional and should only be run if the conditional returns true - essentially, the mouse button is being held down so do something.

Now for the action that will create our bullet if the mouse button is held down, which is the action Instance Create  (from the Instances action library). This should be dragged and added to the right of the "if" action to show that it should only be run if the condition returns true:

Add Action To Condition

To keep things simple for now, the arguments we are going to use in this argument are as follows:

  • Object : obj_bullet (the object to create)
  • X : mouse_x (the "x" position in the room)
  • Y : mouse_y (the "y" position in the room)
  • Layer : "Instances" (the layer in the room editor to create the instance on)

The last argument can be kept blank for now as it's not required, but for future reference, the Target argument permits you to assign a variable to hold the unique instance ID of the instance being created, which permits you to change things on that instance later as well as many other things. We're using the mouse position global variables for the moment as the position to create the instance just so that you can see something being created in the test game, and we are creating it on the layer "Instances". Remember, everything that goes in a game room gets placed on a layer, and in the room editor we can name our layers to anything we require. The layer name can then be used (enclosed in quotes "") to reference the layer in other actions.

The final action block should look like this:

FInal Test Shoot Actions

You can hit the Run button  now and see what happens...

Shoot Test

Layers

Before continuing, we should look at the concept of layers in a bit more depth. The bullet instance we are creating is created using the Instance Create action , which creates the instance and assigns it to the layer ID that you give, - in this case the default Room Editor layer for instances. But... what is a layer? Simply put, layers are conceptual 2D spaces that we can use to store things, and the order in which we have the layers within the room editor will affect the depth at which the instance is drawn:

Layer Depth Example

In the above image, you can see that by changing the layer order we can change whether the player instance is being drawn over the enemy instances or not. Note that if you have several instances on the same layer, then these will be drawn in the manner that is most efficient, normally from the first created on that layer to the last but this is not guaranteed. So, if you want something to appear above or below something else, it should be placed on an explicit layer. The following image is a schematic representation of how layers are rendered to help you visualise what's going on:

Layer Schematic

In our tutorial game, we have just set the bullet instances to use the same layer that the instance of "obj_player" is assigned to by using the layer name "Instances" from the room editor. All objects are placed on layers, and when an instance is created in a room it must always be assigned to a layer, and the layer it is assigned to will affect the render order, ie: whether it is drawn "above" or "below" other things that are being drawn on other layers. We could, for example, have created a "BulletsLayer" in the room editor, and then used that to explicitly say we want the bullets on a unique layer - the action for that would have been simply:

Bullet Layer Example

You can see there that if a layer has been created in the room editor, we can use its name as an identifier to target it within this action (and a few others). We will do this a little later on in the tutorial, so don't worry about it just now and we'll just use the "Instances" layer to start with.

If you want to find out more about the layer functions, press  to open the manual and do a search for "layers".


Better Bullets

Going back to our game, if you press Run  now then you can test our bullet creation actions:

Not-very-good-bullets

Hmmm... That's not really what we want is it? We need to change the actions to make the bullets fire from the player towards the mouse, and not just magically "appear" where the player clicks. To do that, let's first change the Step Event action Instance Create of the object "obj_player" by simply changing it to use the player position (x / y) instead of the mouse position (mouse_x / mouse_y):

Changed Creation Action

Once you have made that change, we need to switch to our object "obj_bullet" (double click  it in the resource tree, or use  /  +  to bring up the Workspace Switcher). We need to add a Create Event to our bullet. Unlike the Step Event that we used in the player object, the Create Event will be called only once when an instance of the object is first created in a room. This makes it an ideal place to set up variables and prepare conditions for how the object is to behave.

To add the event, click the Add Event button and select Create from the event list:

Add Create Event

Adding the event will chain an Action Editor window to the Event Editor ready for use. We want the bullet to shoot off in the direction of the mouse, so we need to add the following actions:

Set Point Direction
With this action we will set the built in direction variable to the direction from the (x / y) position to the (mouse_x / mouse_y) position.
Assign Variable
We now want to add "spread" to the bullets so we use this action along with the function random_range to add or subtract up to 4° to the direction.
Set Speed
We have set the direction so now we use this action to set the speed to 16, which means it will move 16 pixels in the given direction every game frame. The "type" should be set as the direction, as we want to use that rather than the horizontal or vertical component.
Set Rotation
Finally we set the sprite rotation (image_angle) to face the same way as the direction variable.

Adding these into the Create Event of the bullet object should give you this:


Create Event Actions

Go ahead and hit Run  now to see what happens:

Shooting Moving Bullets

That's starting to resemble something that could be called a game, but there is an issue... because we are creating the bullets on the same layer as the player, they are being drawn on top of the player which doesn't look right. So let's fix that now...



The Bullet Layer

As we discussed previously, how things are drawn will depend on the layer order within the room editor, and if we want our bullets to be drawn under the player, we have to create a new layer and add them to that instead of the instance layer that the player is on.

If you open the room editor for our game room (double click  on the resource in the Resource Tree), you will see that by default the Layer Editor is shown docked to the top left of the Room Editor workspace:

Room Editor Layer Properties

Currently we have two layers: "Instances" and "Background". These are the default layers created for any new room, where the background layer permits you to use a colour or a sprite for a single background image, and instances permits you to add instances in to the room.

Currently the player instance is on the "Instances" layer, and we need to add a new layer for our bullets, so click the New Instance Layer button  to create a new layer and name it "BulletsLayer" (to rename a layer, simply slow-click  twice on it).

The layer has been created above the player layer, which means that anything assigned to it will be drawn after the player, which we don't want. To resolve this, click  on the layer and then drag it down the list until it's under the "Instances" layer, but over the "Background" layer.

Change Layer Order

Layer order is actually defined by a value, called the "depth" value. If you look at the Layer Properties window (by default under the Layer Editor) you can see this value shown, and as you change layer order it will change too. You can change this value if you wish, but by default it's locked and handled by GameMaker Studio 2 automatically.

Layer Depth

Essentially, the higher the depth, the "nearer" the camera it is and the lower the depth the further away, so a layer at depth -200 will draw under a layer with depth 300, for example.

We need to go back to our object "obj_player" and change the creation code to look like this:

Change Create Instance Action

As mentioned previously, you can use the layer name (in "" as a string) to tell GameMaker Studio 2 what layer to use, and now if you test the game again, the bullets will be created below the player object.



Bullet Timing

At the moment, our bullets are created 1 per game frame (every time the game loops round and performs the Step Event again), which is a bit too fast for what we require. So now we need to slow the rate of fire down a bit. For this we need to add a Create Event for the object "obj_player", and in it add the following action:

Assign Cooldown Variable

All we are doing here is preparing a variable called "cooldown" for use later on in the game - remember, the Create Event is only run once when the instance is first created, so this variable is being initialised to 0 once only. We've seen built-in variables already, but this is one you are creating and it's called an instance variable. Instance variables are valid for any event in an instance and can be changed or read in other action blocks. However they are also unique to each instance, so if you have 100 instances of "obj_player" in your game, they will all have an instance variable "cooldown" since you defined it in the base object, but each one could have it set to a different value throughout the time the game runs.

We are now going to use this variable in the Step Event of the player object to control how often the shooting occurs, like this:

Nesting Ifs

What we have done is "nest" an if variable action  within the mouse down action, so it now reads "if the mouse is held down, and if the variable cooldown is less than 1... {do something}". That "do something" is create our bullet instance and then set the variable cooldown to 3 (using the actions Assign Variable ), which means that the next game frame, the if variable condition will fail and no bullet will be created because "cooldown" is not less than 1.

It can be a bit tricky to reorganise your actions so the following animation shows you how to add these actions correctly:

Adding Actions

There is a problem with this however... We don't count down the variable cooldown anywhere, which means we will fire one bullet and no more since it will be set to 3 and the subsequent "if" check will fail. So we need to add another Assign Variable  action after all the others and outside of the "if" checks:

Subtract From cooldown Variable

Note that we have checked the "relative" checkbox. By doing this we are adding -1 relative to the current value, ie: subtracting 1 from the current value. If this was not checked then we would be simply setting the cooldown variable to -1.

Your full action list should now look like this:

Full Action List

If you test the game again now, you can see that the bullets fire a bit slower, but for our purposes it still seems too fast. This is now an easy thing to fix, as it requires a simple change to the number of frames we wait between creating each new bullet instance. So, change the "3" in the Step Event Assign Variable action  to 10 and test again.


Summary

That brings us to the end of the Shooting Section of the "My First Game" tutorial. Let's just pass over the core concepts and things that you should know after completing this tutorial:

  • How to use multiple "if" to check different conditions
  • How to create a new instance using an action
  • How to create new layers and change layer order in the Room Editor
  • How to create an instance variable and use it in other actions

Our project is still not quite a game, as it's missing a few important things... One of which is an enemy to shoot at! So, the next section in this series will see us creating a new object for the enemy and having it react to the player and the player bullets...


Enemies

Game Speed

You've made it to the Enemies Section of our "My First Game" series of tutorials, and you're doing well! You should now have a player ship that can move and shoot, and bullets that are timed to come out at regular intervals. So, what next? Well, most games have some form of goal to achieve and more often than not this involves shooting something, so in this tutorial our goal is to add in some enemies for the player to shoot.

NOTE: If you close the accompanying video then you can get it back by clicking here

Green Furry Enemies

Before getting to the part where we add the enemies, however, we are going to take a moment to speed the game up and make it feel more responsive. We could do this by changing the amount of pixels that player moves when the arrow keys are pressed, along with changing the bullet speed and the timer instance variable we use... but there is an easier way!

As mentioned briefly in a previous tutorial, all games run at a speed which is defined by the number of times the game loop runs in a second. Each loop is called a game frame and so we call the speed at which a game runs the game Frames Per Second (FPS). By default this is set to 30 by GameMaker Studio 2 for any new project, which is fine for puzzle games, or games that don't require fast response times or even for mobile games, but for arcade style games like ours a preferred value would be 60.

The game Frames per Second setting can be changed in the Game Options which you can open from the button  at the top of the IDE, or by going to the Resource Tree Main options item:

Options Window

As you can see from the image above, here you can change a few things that will affect how your project will run, including the game FPS value. So, set this to 60 now, then click on Apply and close the options then test the game again. You'll see that everything is much faster, and smoother when playing.


The Enemy Object

The workflow for creating the enemy object is the exact same as that which we used for the player and bullet objects, so we'll simply list the steps here, as you should be familiar with how it goes:

  • Create a new sprite resource
  • Call it "spr_enemy"
  • Import an image (remember, while following this tutorial the file explorer should take you to the TutorialResources folder automatically where you can find the sprites used in the "Images" sub-folder). If you have any issues, you can also find the images here.
  • Set the origin of the sprite to the middle (use the drop down menu)
  • Create a new object resource
  • Call it "obj_enemy"
  • Assign the enemy sprite we just added to the new object

If all has gone correctly, your workspace should look like this:

Workspace

We now add a Create Event for our enemy object. In this event, we will add the following Assign Variable action :

Assign hp Variable

"hp" is an instance variable that we want all instances of this object to have, and it will store the "health points" for the enemy object. Every time we shoot the enemy, we will deduct 1 from this value until it reaches 0 and it is removed from the game. Keep in mind that instance variables need to be initialised before use, and so that is why we have them in the Create Event, as that event is run for every instance the moment it is created in a room and the event only runs once so the variable is only set once at the start.

Next we need another variable for the speed we want the enemy to move at:

Assign Enemy spd Variable

This variable will be used to define the movement speed of the instance. Note that we are not setting the "speed" value directly, but instead will be using this custom variable to set the speed. Why? Well, we could just use the value 1.5 in all future actions when we deal with the instance speed, but if we want to change that value, it would mean searching through all the actions and manually fixing it. This can be very time consuming and error prone, so we use the instance variable instead to store the value. This means that should we want to change it, we only need to change it in this one event, and all the rest of the actions will "just work".

We now need to add a Step Event to the enemy object. This event runs every game frame and in it we are going to check for a player instance in the room, and if one is found we'll move towards it. The actions will be like this:

Enemy Step Event

Let's just go through the actions here one at a time so you can see what is happening:

Instance ExistsWith this action, we check to see if there is an instance of the player object in the game room because later we want to access certain variables from that instance. This is a bit of forward thinking on our part, as we will eventually have the player "die" in our game, removing its instance from the room, and if we try to access the variables of an instance that doesn't exist, then the game will error and crash.

Assign VariableWe know that an instance of the player object exists, thanks to the above check, so that means we can access its variables. The method shown here is the "point" method for accessing variables in another instance. Simply provide <object_index>.<variable> or <instance_id>.<variable> and you can get or set values from another instance, as long as it exists in the room (see the comments above checking if an instance exists above).

Set SpeedWe have set the direction so now we use this action to set the speed to the variable we defined in the create event.


So, if there is an instance of the player, we then tell the enemy to move at the speed of the "spd" variable towards it. Finally we want to add this, outside of the "if":

Set Rotation

You've seen this action before in the other objects, so you should know what we're doing here... The full action list now looks like this:

All Enemy Actions

You should open the Room Editor now on our game room and add a few instances of this enemy object into it (click  and drag from the resource tree into the room area), and then test the game:

Enemy Test


Collisions

At the moment, the enemies just follow the player around and don't actually do or react to anything else. We need to fix that, so to start with we need to edit the Step Event again. We are going to expand on the current actions to include a check to see if the "hp" variable we initialised previously is less than or equal to 0, and if it is we are going to destroy the instance (remove it from the game room). This is done using the following actions, which you should add in after the current ones:

Check Health Variable

The next thing to do is to make the "hp" variable actually go down, as currently that check will always return false since we only set the "hp" to 5 and nothing else.

Open up the object "obj_bullet" (if it's not open already). We need to add a Collision Event here to detect the collision between the bullet (the calling instance) and "obj_enemy" (the colliding instance):

Adding A Collision Event

Now, in this event we will need to affect the "hp" variable of the colliding instance, and we saw that we could do this using the "point" method previously. However that won't work in this case, as there are multiple enemy instances within the room and GameMaker Studio 2 doesn't know which one you actually want to affect. So we can't write:

Assign Variable Error

That code will subtract 1 from ANY of the instances of "obj_enemy" in the room, and so is best used when we know that there is only one unique instance to be accessed. Instead we need to first of all tell GameMaker Studio 2 to change the "scope" of the following actions to affect the "other" instance in the collision using the action Applies To... . When you drag this into the action workspace you then have to click the little arrow to the right and select a "target". The target can be an object, an instance or one of a couple of keywords, which in this case we want to be "other". Using that we are telling GameMaker Studio 2 that the following action blocks are to be run as if they were part of the other instance in the collisions actions - in this case the obj_enemy.

Affecting The Other Instance

Next we add in the Assign Variable action just as shown above, only we chain it to the right of the Assign to... action, as we did for an "if":

Chain Action To Assign To...

Finally we want to destroy the bullet instance by dropping an Instance Destroy action  after (and outside of) the Applies to... action, so the final Collision Event looks like this:

Final Action List

After we take the point of off the "hp" variable, we then call the action to destroy the calling instance (the bullet). Test game now and see what happens...


Collision Masks

While you've been testing your game, you may have noticed that the bullets don't often actually appear to hit the enemies when they disappear... yet the hit is being registered, and the bullet is disappearing and the enemy "hp" is being affected. What's happening?

To answer that we need to back to the Sprite Editor and explain another of its features - the ability to set up a collision mask. So, open up the bullet sprite now and click the section labelled Collision Mask:

Collision Mask Interface

This section of the sprite editor permits you to define the area of the sprite that will be used to detect collisions, where a collision is defined as when two collision masks overlap at any point. By default, this will be set to Automatic, and you can see that in the preview window GameMaker Studio 2 has added a darker rectangle to show the area of the sprite that will be used for collisions by default. However we want to edit this as it is too large for what we need, which means you have to click the Mode button and select Manual. This will open up the options to edit the collision mask, permitting you to change the mask shape and set the values required for the area it covers. We are going to use the rectangular collision mask, but we need to change it's size. We could do this by changing the values shown for left, top, right and bottom, however you can edit the collision mask directly in the preview window by simply dragging the little box "handles" around:

Edit Bounding Box

What we want is to achieve is a collision mask that covers only the "head" of the bullet so that the rest won't register, something like this:

Bullet Collision Mask

You now need to open the other two sprites (for the player and for the enemy) and edit their collision masks too, as in the image shown below:

Player And Enemy Collision Mask

Note that we have left the player collision mask a fair bit smaller than the sprite itself. In most arcade games, the collision mask is kept smaller than the sprite to give the player a bit more room for error, and in this game we will do the same.


Player Collisions

Before we end this tutorial, let's quickly add in a collision for the player colliding with the enemy. This won't be the final way we do this, but for testing and to give a feel for how the game will pan out, it is fine.

To start with open up the object "obj_player" and add a new collision event with the object "obj_enemy":

Collision With Enemy

In this event we need to add the following action to Restart The Game  (from the Game action library):

Restart The Game

All this code does is (as you might imagine) restart the game the moment an enemy instance "touches" the player instance, meaning that we now have to not just shoot the enemies, but dodge them too. This is a very basic mechanic and we'll refine it more in later sections, but for now it's enough for us to test and get a feel for how everything plays.

You should run the game again now, and you'll see that the experience is quite different to what it was before. The collisions are solid and look better, and there is a certain skill required by the player to avoid the enemies while shooting.


Summary

In this short section we have added yet another object to our game, the enemy, and got things feeling a bit more like how an arcade game should feel. The main points you should have learned from this are:

  • Where the Game Options are and how to change the Game FPS
  • How to access variables in other instances using the "point" method or using the Applies To... action
  • How to edit the collision mask for a sprite and what effect it will have on the game
  • How to add collision events and the keyword other
  • How to restart the game

That might not seem like much, but the core concepts here are probably amongst the most important you can learn. Being able to access variables in other instances is incredibly useful and very powerful, and it's important to know how and when it can be done. The same for the collisions mask, as having the wrong collision mask in your game will seriously affect the gameplay and the fun of the player.

In the next section , we are going to look at making the visual aspect of the game nicer, in particular adding backgrounds to the arena, as well as making the arena bigger and having a "camera" follow the player around...


Tiles and Views

Tiles and Views

This is the Tiles and Views Section of our "My First Game" tutorial, and if you've done the first three sections then you've already got the beginnings of a small arena shooter game. Your player can move and shoot, and you have enemies that attack the player. However, it's not very pretty, since everything happens on a plain black background. It's also not a very big play area for the player to move around in, making the game feel cramped. In this section we will change that by making it more attractive to the player using tiles and also expand the play area using cameras.

NOTE: If you close the accompanying video then you can get it back by clicking here

This section is a bit different to previous ones in that we won't be using any Drag and Drop™ actions. Everything we want to do can be achieved using only the Room Editor, so to get started double click  the room "rm_game" in the Resource Tree to open the Room Editor workspace.


Tile Set Sprites

To add a background to our game we want to use a Tile Set resource. Tile Sets are all based on sprites, and although so far we have only used sprites for game entities like the player or the bullets, we can also use sprites for backgrounds and tile sets, which can also be animated and do other interesting things.

First thing to do is create a new Sprite resource (right click  on the Sprite resource folder and select Create). Then import a tile set image. We are going to use the following image:

Example Tile Set

You can get the above tile set from the TutorialResources folder that the tutorial made automatically, in the "Images" sub-folder, when you click the Import button (if you have any issues, you can also find the images here).

The tiles we are going to use for the game are 128x128 pixels each, all placed on the same image in a grid. Tile Sets are always comprised of a single sprite image, and must always be based on a grid, although the grid does not have to be square, just regular, ie: you can have 24x96 tiles, or 32x32, etc... as long as each part of the tile set image is on a grid it can be used in GameMaker Studio 2 as a tile set.

Note that the top left corner of the tile set sprite is empty. GameMaker Studio 2 will always use the first tile of a tile set as a "blank" tile, which is what is placed by default as an empty tile. When you add a tilemap layer in the room editor, which we'll cover in a moment, it will be empty and you won't see anything, but it's actualy filled with these "blank" tiles, and when you start to paint tiles onto the tilemap layer, if you delete a tile, it's not actually being removed, but instead it's being changed for this "empty" tile too. Note that even if the image you supply has non-transparent pixels in this first grid cell, they will not be drawn, so when making tile sets keep this in mind and just leave this first tile blank.

You can name this sprite now, something like "spr_background", and close the sprite editor before continuing (we don't need to set the origin of this sprite nor any of the collision properties as they are not relevant for tiles).


Making a Tile Set

We now need to make a new Tile Set resource, which is done the same way as for sprites and objects, etc... by right clicking  on the Tile Set resource folder and selecting Create. This will open the Tile Set Editor:

Tile Set Editor

The tile set window is comprised of two parts to start with: the main Tile Set Editor window which has the Tile Set Properties window chained to it. To start with lets name the tile set "tl_background" and assign it the sprite we just created. You can assign the sprite by either clicking the Select Sprite button in the Properties window, or the button marked No Sprite in the Editor window.

Assigning A Sprite To A Tile Set

When you import the image, you'll see that it is covered in a grid that is 16x16px per cell. This grid shows the way that the image will be split to create the final tile set cells, and if you have used the tutorial image you can probably tell that the current settings are way to small for the image we are using.

Tile Set Grid 16x16

In the above image you can see we have marked the first two sections of the tile set properties. These control the tile set cell width and height and setting these will dictate how the tile set image will be split up and how it will be displayed when painting it into a room tilemap layer. For this tile set you need to set each of these values to 128px.

The rest of the values can be left at their default settings, as they are used for creating "offsets" and "split distances" between individual tiles in a tile set image. Basically, some tile set images may be created with "empty" areas around each tile and so you can set the pixels or cells between each individual part of the image here. However our tile set has all the tiles packed right beside each other, so we don't need to worry about this.

Our tile set is now set up and ready to add to a room...


Tilemap Layers

We need to go back to the Room Editor workspace now, as we want to create a new layer called the Tilemap Layer. We currently have two instance layers (one for the player and the enemies, one for the bullets) and a background layer. We want to add a tilemap layer between the background layer and the bullet layer so click the Add Tilemap button  to add the layer first, then click  on it and drag it to position it between those two.

Add A New Tilemap

As with almost everything in GameMaker Studio 2, you can give this new layer a name like "TilesLayer" or something, and then you can go ahead and assign the tile set that we made previously to it. This is done by going to the Layer Properties window - which is opened by default on the left of the room editor when you select any layer - and then clicking the button that says "No Tile Set" which will open a window to let you select the tile set to use:

Choose A Tile Set

The tile set selected will now open on the right of the room editor workspace and you can click on any of the tiles to select it for "painting" into the room:

Painting Tiles

We now need to paint the tiles in a way that makes sense for the room and the tile set chosen, so select the appropriate tiles to make the final tilemap layer look like this:

Final Tilemap Layer

A few things to note here:

  • Tiles will always be added to a grid the same size as the tile set assigned to the tilemap layer
  • You can only place one tile per grid square
  • You can select the empty tile to paint with and remove existing tiles, but you can also use the right mouse button
  • You can move around the room using the middle mouse button  and moving the mouse

You can test the game now and it should play exactly the same as it did before, only now we have a nicer background for the action to happen on. In a later tutorial in this series we'll look at creating a "wall" around the arena so the player can't leave the room area, but for now we have what we wanted.


Room Size

The play area for the game is a bit small so the next thing we are going to do is make the roomsize a bit bigger. This is easily done by simply changing the width and height of the room from the Room Properties, which by default can be found at the bottom left of the room editor window:Room Properties

You can see that the default width and height here are 1024x768, but that's too small so let's just double the width value to 2048 by clicking  on the input box and changing it. After you change it you will see that the room in the editor has now expanded to twice its width (you can use the zoom controls  to expand the viewable area if you can't see the changes, or alternatively hold down  /  and then use the mouse wheel  to zoom in/out).

Room Width

If you run the game at this point, you will find that you now get a massive game window that is way to big for most people to actually play in, so we need to sort that out using cameras. However before we get to that, you should fix the tilemap layer so that it covers the whole room:

Fixed Tilemap


Cameras and Viewpoints

To prevent the issue with the huge window we need to tell GameMaker Studio 2 to only show a portion of the game room using a camera view. We can set this up from the room editor too, from the section titled Views in the Room Properties. Clicking on that section will expand the different properties:

View Properties

The first thing to do here is to check the box beside Enable Views. No matter how you set things up, if you don't enable views then nothing will change, so this is very important! Next you need to expand the section on View 0. You can have multiple camera views in a room, and they can all be enabled and displayed at different positions (permitting, for example, a two player split screen game, with a camera view for each player), however for our game we only need one, and that's the camera View 0.

View 0 Expanded

There are a lot of options here, but the first thing we need to do is switch the view "on". This is done by checking the box labelled View Visible. Even if you have enabled views, if you don't have one that is set to be visible you won't get the desired result. Once it's been checked, you'll see a rectangle appear in the actual room preview to show you where the new view camera will be placed:

View 0 Enabled

This view camera "rectangle" is defined from the view properties, with the xpos and ypos values being the top left corner of the view, and then the width and height defining the size from that point. You can also set the the camera view port, which is what defines the area of the screen that will be used to display the camera view. Basically, you can set a view camera to be any size, and then set the view port to be a different size and the camera view will be scaled to fit in that space. So you can have a camera view that is 480x320 (for example) but make the camera port 960x640 and the camera view will be scaled up to fit. However for our game we are keeping things simple and all those values can be left at their default settings.

The final thing we need to do is set the Object Following. By default a view camera is static, ie: it won't move unless you code it to, but we can set it to follow an instance of an object automatically and without code using this button:

Object Following

Once you've set it to follow the player object, we also need to set the Horizontal Border and Vertical Border values. These dictate how close to the edge of the view the instance needs to be before the view camera will move to follow it. At the moment it's 32px, which means that the player would have to move right up to the edge of the view camera window before it will move to follow, which in an arena shooter like ours is just too small... we want it to move before that so that the player can see what is around them. So, set those values to 256px each:

Object Following Border Values

Notice we leave the two "speed" values at -1... If we set this then we are telling the view camera to only move by a specific amount each game frame, so that if we set it to (for example) 5, then the view camera will follow the player only 5px per game frame. This can be really useful and can give a nice "catchup" effect if the instance being followed moves faster than the values given, but for our game we want the camera to always stay centered on the player, so we leave it at -1, which is essentially telling the camera view to move "instantly" to the instance being followed position every game frame.

If you run the game now you can see how this all works to make the camera follow the player while they explore a larger room and shoot the enemies...



Summary

Getting to grips with the room editor is essential if you want to get the most out of GameMaker Studio 2, and there are many, many features to it. In this section we've covered two of the main ones, the layer system - and in particular tilemap layers - and the camera views system. Let's quickly cover the main points you should have picked up while going through this:

  • How to set up a tile set resource
  • How to create and order layers in the room editor
  • How to paint tiles into a tilemap layer
  • How to enable and set up view cameras
  • How to make a view camera follow an object instance

Our arena shooter game is starting to look pretty good now, and we have all the essentials in there. However it's missing one or two things to take it from a prototype to a finished game, one of which is a scoring system which is what we'll cover in the next section of this tutorial...


Scoring

Score Controller

You've made it to the Scoring Section of the "My First Game" tutorial and in this section we are going to look at an important aspect of any game... keeping score. We're going to create a score for the player to use as a measure of how well they are doing in the game, and not only will we be keeping score, but we'll be using the different functions for drawing text to show it to the player as well. So, the player shoots an enemy and "kills" it and the game will award them a certain number of "points" which we'll add to their score. This score will then be displayed prominently at the top of the screen...

NOTE: If you close the accompanying video then you can get it back by clicking here

To keep things clear and easy to manage in our arena shooter project, we need to make a new object to act as our main "controller" object for the score. You should be familiar with how to do this so go ahead and make one now and call it "obj_score":

  • Click the right mouse  on the Object resource folder
  • Select "Create" to create a new object
  • Name the object "obj_score"

The object "obj_score" will be our controller object and so we don't assign a sprite to it since we want it to draw other things (like the score text). Not assigning a sprite to an object means that when we run our game with an instance of that object in a room it will not be drawn, but that doesn't mean that it isn't doing anything. In this case our controller object won't be drawing a sprite but it will (by the end of this tutorial) draw some text and manage the player score value and certain game events.

Now we need to add an instance variable to the object in the Create Event which will be used to hold our score value. So, add a Create Event now, and in the action editor window that pops up drag the Assign Variable action  and set it to the following:

Assign a score variable

This gives us an instance variable with the name "thescore" and sets its value to 0. It is worth noting that previous versions of GameMaker had a built in global variable "score" ehich could be used for these things, but it meant that you could only ever have one score value for the entire game (which was limiting and it's generally better to have unique variables for score in each instance - for example, if we wanted to make a two player game then we couldn't use the global score and would have to make instance variables for each one, the same as we have here). GameMaker Studio 2 still has the "score" variable for backwards compatibility, but it has been deprecated and should not ever be used.

With that done we need go ahead and add a Draw Event.



The Draw Event

We are now going to add a Draw Event to our object. Click  the Add Event button now and select the Draw Event category:

The Draw Events

As you can see, there are multiple draw events to choose from, but for this we simply need the general draw event, which is the one at the top of the category list (highlighted in the image above). The general draw event is the one that GameMaker Studio 2 uses when it default draws your instance sprite. What does this mean? Well, so far we haven't added any Draw Event to any of our instances, and yet they all draw their sprites to the screen when we run the project. This is because when you don't add a general Draw Event to an object yourself, GameMaker Studio 2 will automatically assume you want to draw the sprite assigned to the instance along with any transforms (like colour or alpha or scale) that you have added. Essentially, the general Draw Event defaults to using the Draw Self action .

That action will also draw the assigned sprite along with any applied transforms, just like the default drawing for an instance when it has no Draw Event. Now, when you add a general Draw Event to an object and in it add some action blocks, you are telling GameMaker Studio 2 that you want to handle what is being drawn and GameMaker Studio 2 will no longer draw anything except what you have put in the event, so it won't draw the assigned sprite unless you tell it to (and you can draw any sprite, it doesn't have to be the assigned one).

The general Draw Event (and all other draw events) will be performed once for every game frame, much like the Step Event will, and note that you can have unrelated actions in the draw event as well as draw actions (but it is recommended that you keep this to a minimum and use the Step Events instead where possible). However, all drawing must be done in a draw event, and in general placing draw functions in any other event will not work.

Just before we continue, it's worth noting that the Draw Events other than the general drawing, will not affect the instance default drawing, so that you can, for example, have no general Draw Event but have a Draw End Event and the instance will still default draw the sprite and whatever you have added into the Draw End Event. If you want to know more about the different events in the Draw Event category, you can press  to open the manual and read up on them in the section on the Object Editor.


Local Variables

In our draw event we want to draw the score text on the screen at the same position at all times. This means that we can't use an absolute room position since as the camera moves about, the text will be lost off of one side or the other of the camera view. So what we need to do is draw the score text relative to the view camera. To make this easier we are going to use a couple of local (temporary) variables. We already know about global scope variables (they belong to the game, not any object in particular and can be read/set by all at any time), and instance scope variables (which are unique to every object instance, but can be accessed by other objects using the "point" method or "with", as discussed in the Enemies Section)... but there is a third class of variables called local or temporary variables which we are going to use now.

A temporary or local variable is simply defined as one that is "local" to the script or event that is using it. This means that it is created when you use the action  and then discarded again at the end of the event or script that created it. This is useful for many, many things, not least of which is storing one-off values from calculations and saving memory resources. In this case we want to use local variables to store some return values from functions that we will use in the code.

Go ahead and drag the Declare Temp  action into the general Draw Event action workspace now and fill in the following:

Assign View Camera to a Temporary Variable

Here we are getting the ID value for the camera assigned to view port[0] using the built-in global scope array view_camera, and then storing it in the temporary variable "vc". You can have multiple view ports active in a room (up to 8, starting at 0, so it's view_camera[0 ... 7]) and can assign a camera to each one, so referencing (for example) view_camera[3] will mean you are dealing with the camera assigned to view port[3]. In this case we use view port[0] since that is the one we set up in the room editor in the last section.

We then need to get the position of the view camera within the room space, so we use the Declare Temp  action two more times:

Assign View Camera Position to a Temporary Variable

There is no action available for getting the position of a view and so we have to use a function in the "value" argument. These functions will return the (x/y) position of the view and store each one in the temporary variables "cx" and "cy", and note how we use the previously declared temporary variable here. We want to get one final value now so that we can position the text correctly in the middle of the screen, so add a final Declare Temp  action:

Assign View Camera Width to a Temporary Variable

Now we have those values in our temporary variables, actually drawing the text requires a single action - the Draw Value action :

Draw The Score As Text

All we are doing here is taking the position of the view within the room and then using those values to position the text we want to draw at a relative position, meaning that it will now move with the view camera (specifically, it'll always be at the top of the view port and centered). With that done you should have a full set of actions that looks like this:

Full Action Block

You could drop this instance into the game room, but all you'd see would be a "0" on the screen since we don't actually add to the score value yet, so let's do that now.


Setting Score

To get our score to go up as we play, we need to add some extra actions into the Step Event of the object obj_enemy, so open that now if it is not open already. We currently have the following actions in that event:

The Current Enemy Step Event

We need the enemy to add a value to the score object variable "thescore" and so for that we will use the Applies To... option in an action. We covered using the Applies To..." action  in the Enemies Section where we used the "other" keyword to refer to the other instance in the collision. However "other" in that context only works for the collision event, and we want to apply an action to an instance in the Step Event, so we need to change the scope of the action we are going to use.

To start with, drag an Assign Variable action  into the action workspace and position it above the Destroy action :

Add Assign Variable Action

We want to set this action so that it changes the "thescore" value in the object obj_score. Now, as shown before, we could pull in the Applies to... action here, but for a single action like this it's not necessary as we can change the scope of any action by clicking the little arrow at the top right, like this:

Set Action Scope

Note how the action now has a different coloured outline? This means that the action is going to work on a different object (in this case we have selected obj_score as the object to target). Now set the action as follows:

Set Action Values

Note that when using an object index like this, if there are more than one instance of the object in the room when the code is run it will run for all instances of the object. Using obj_score in this case is fine because we are only going to have one of them in the room, but you can use this method to target a single instance if you target an instance ID (which you can get from the Room Editor or by certain functions), by placing it in the text field at the top which says Expression:

Expression In Applies To

Our action will now add 5 onto the thescore variable every time an enemy instance is destroyed, and we can now add the score object into our game room. To do that open the room resource (double click  on it in the resource tree), and then drag an instance of the object obj_score into the room and place it anywhere (make sure that you have selected the "Instances" layer first). Since it doesn't have a sprite it will be shown with a question mark icon .

Score Object With ? Icon

You can play the game now and you will see the score displayed at the top, and if you shoot and destroy the enemy it will go up by five. You might have to squint a bit though, as it's written rather small and isn't very easy to read, so lets fix that now.


Styling Text

We need to style the text on the screen to make it more readable and nicer to look at and for that we'll start by adding a new Font Resource. If you right click  on the Font resource and select Create it will create a new font resource and open the Font Editor:

The Font Editor

Following the naming convention <prefix>_name we'll call this new font fnt_score. You can then go ahead and select a font from your machine to use as the game font and then in the editor set the style to bold to make it stand out that much more (if the font you select permits it), and set the size to 24 to make it bigger. Note that in the Font Editor you have a preview window that by default shows "Hello World". You can actually delete this and type in any text to get a preview of how it will look in the game. The other options in the Font Editor are outside of the scope of this tutorial, but you can read up on them by pressing  to open the manual and going to the section on the Font Editor.

The Font Editor Settings

You can close the font editor now, as the next bit of styling we need to do is done through code. By default GameMaker Studio 2 will use a draw colour of white for everything, but at various points in your game you may wish to change this, and it's good practice to explicitly set the draw colour before drawing anything, so that is what we are going to do now as well as draw the text itself. Go back to the controller object obj_score and make sure you have the general Draw Event open as we need to edit it.

The first thing to do is tell GameMaker Studio 2 that we want to draw with new font resource, so before the Draw Value action we need to add a Set Font action  like this:

Set Font

As the action name implies, this will set the font for drawing any text. Note that this will set it for the whole game and all subsequent text will be drawn using this font even if you don't use this action anywhere else, so if you want to use various fonts in a game you must call this action before every item that needs drawing, but if your game only needs one font then you can call this action in a controller at the start of the game once only.

We want to set the colour that the font is drawn in too, so now add the action Set Draw Colour  like this:

Set The Draw Colour

The default colour is white, so we don't need to change anything there (although you could set the colour to anything you want by clicking the colour swatch in the action which will open a colour picker for you or by giving a hexadecimal colour value), but we need to un-tick the "Use alpha from colour" option, as we want the text to be drawn solid white regardless. Again, like the Set Font action, this will set all further drawing to use the given colour (and not just for text either, this will affect shapes that are drawn and few other things), and so can be called once at game start if the colour isn't going to change, or once every time that you want to draw with another colour.

With that done, the full action list for the general Draw Event should now look like this:Final Draw Event Actions

You can now run the game again and you should see that the score is much more visible, maintains it's position and goes up when an enemy is destroyed:

Final Game Screenshot


Summary

In this section we spent some time showing how to add text to your game and increment the score, which shows the player how well they are doing as they play. The main points you should have picked up while working through this section are as follows:

  • How to use the Draw Event
  • How to use (and understand) temporary (local) variables
  • How to change action scope using Applies to... from within the action
  • How to create a font resource and use it
  • How to set a font and a colour for drawing

That might not seem like much, but with this knowledge you can start to set up more complex displays for your player to include any number of written details, and format it to follow the view camera at the position you want. It's worth taking a moment to look at all the different draw actions for text that are available to you (press  to open the manual) as they permit you to scale the text, or limit it to a specific string width (number of characters) and many other things. In fact, you can save this project file and then save it again under a different name and experiment a bit with the different functions to see what they do (you can load the original saved tutorial later to continue).



Sound

Sounds Files

This section we are going to dedicate to adding some sound to our game. Basic sound is incredibly easy to do and so this section will be a short one, but what you'll learn can be used anywhere in your own projects. At the moment the game is looking good, but it has no sound effects, and sound is an essential part of any gaming experience so let's go ahead and rectify that...

NOTE: If you close the accompanying video then you can get it back by clicking here

In this tutorial we will simply be adding a single sound effect when you destroy the enemy instances, so you can use any sound effect that you have on your hard-drive or you can use the one that we have supplied along with the tutorial, which will be found when you open the file explorer in the TutorialResources folder, in the "Sound" sub-folder (if you have any issues, you can also find the sound here). If you make your own sound effect, you should export it as a *.wav, an *.ogg or as an *mp3 format sound. However note that in general you want all sound effects to be *.wav format and all music to be *.mp3, and *.ogg can be either, but is generally preferred for longer sound effects and music too.


The Sound Editor

Creating a sound resource is exactly the same as creating any other resource. Simply go to the Resource Tree and right click  on the Sound resource and click Create. This will open up the Sound Editor:

The Sound Editor

First thing to do is the name this new resource, and since it's for when the enemy dies we'll call it snd_death, so name it that now. You can then click on the Import button  to bring up a file selector and look for an appropriate sound which as mentioned at the start should be a *.wav format file (remember, while following this tutorial the file explorer should take you to the TutorialResources folder automatically where you can find the sounds used in the "Sound" sub-folder). If you have any issues, you can also find the sound here.

Once you have named the resource and added the file, you can use the audio preview buttons in the editor to listen to the sound and set its volume:

Playback Controls

The rest of the options here we can leave at their default values, but if you want to find out more about them then hit  to open the manual and go to the section on the Sound Editor. You can close the Sound Editor now as we are finished with the resource and are ready to add it to our game.


Playing A Sound

Playing a sound is really simple and requires a single action, the Play Audio action  from the "Audio" library. We are going to place this action into the enemy object obj_enemy, specifically in the Step Event, just before we destroy the instance. So, open this object now for editing and go to the Step event and add this action just before the Destroy Object action :

Add A Sound

With that added all you need to do is select the sound to be played from the menu (there will only be the one sound that we have added), and there is no need to check the "Loop" checkbox, as that will make the sound loop continuously until the game ends or we call an action to stop it. Generally this is what you want for music or ambient effects like a wind or waterfall sample, but not for single sound effects like this.

Play A Sound

You can test the game now and kill a few enemies to hear the sound play.


Pitch

When you play the game you should here the sound being played every time the enemy is destroyed, however the sound will quickly become tiring to the ear of those that play the game. We need to "spice it up" a bit and one of the easiest way to do this is to simply change the pitch of the sound.

So, still in the obj_enemy Step Event, and before the action for playing the sound, we need to add the action Set Audio Pitch :

Add Change Pitch Action

When you use a sound effect or music in GameMaker Studio 2 it is played with a pitch value of 1. This is an arbitrary number that simply tells GameMaker Studio 2 to play the sound "as is". If you lower the value of the pitch to say 0.7, then the sound will play at a lower pitch and a value higher than 1 like 1.5 will play it higher. In the action above we will use the random_range function to give us a random value between 0.8 and 1.2 for the sound effect pitch, and so every time it is played it will sound slightly different. This is a great method to add more life to your games and can be applied to almost any repetitive sound effect to make it more interesting and realistic.

The Set Audio Pitch  action should now look like this:

Change Sound Pitch

Note that if you set the pitch anywhere in code then the referenced sound will always play at that pitch unless set again, which is why we call this function not once at the start of the game, but every time the sound is going to played.

Play your game again now and note how the sound changes every time you destroy an enemy.


Summary

In this short section we have added a simple sound effect to the game and made it a bit more interesting by changing its pitch every time it plays. The main points you should have picked up while working through this section are as follows:

  • How to add a new Sound Resource
  • How to play a sound
  • How to change a sounds pitch

It's not much for such an important aspect of any game, but surprisingly those two actions are about all you'll need for adding sound effects into your project. If you want to, you can experiment some more now and add some extra sounds into the game for when the player shoots and moves or when he dies. Just remember that before you start experimenting, save this project file and then save it again under a different name and experiment a bit with the renamed file before loading the original to continue with the tutorial.


Title Screen

Title Page Sprites

When you start a game, you aren't normally just dropped straight into the action, but instead you are usually presented with some kind of title screen. In this section, we are going to show you how to set up a basic title screen for your game using a new room and with some extra graphics.

NOTE: If you close the accompanying video then you can get it back by clicking here

To start with we'll need a couple of sprites. One for the background, and one to show the game title, so make a new sprite now and import the "bg_tile_dark.png" image from the TutorialResources folder (if you have any issues, you can also find the images here). As usual, name your sprite something appropriate like "spr_darktile" and then close the sprite editor.

Dark Background Tile Sprite

We have no need to change any of the properties for this sprite so you can close it now and then create another one and call it "spr_titlescreen". This sprite will hold the title screen text graphic, so open the tutorial assets folder and load the sprite "titlescreen.png".

Title Screen Text Sprite

With this sprite we need to change the origin. We've covered this previously, but just to remind you, simply click  on the Origin drop down menu and select Middle Center to position the origin in the exact center of the sprite

Title Screen Text Sprite Origin

You can close this sprite now and we'll move on to creating the title screen room.


Title Room

At the moment, our game just starts in the main game room, but we want it to show a title screen and have the player do something like press Enter or click anywhere to actually start the game. To achieve this we are going to use another Room Resource, so right click  on the Room resource folder and select Create Room to make one. The new room will be added after the current one:

New Room Resource

We'll call this new room "rm_titles". There is a minor problem that we have to fix now, though... GameMaker Studio 2 will run rooms in consecutive order, meaning the room at the start of the room resource list is the one that will be shown initially when we start the game. This means that we now have to re-order the rooms so that the title room is placed before the game room.

Reorder Rooms

Notice that when you reorder the rooms there are actually two different places where you can drop the room when you click  and drag. The first is dropping it on another rom (the room being dropped on is highlighted), which means that you want the selected room to become a "child" of the other room, and the other is dropping it over a room (where a bar is highlighted above the room), which will place it in the room order. Making child rooms is an advanced and powerful feature, but outside the scope of this tutorial, so just drag it into the position above the room "rm_game", as shown in the animation above for now.


Title Room Properties

By default the room will have been created with a Background layer, so select that now. This layer will be used to show the background tile sprite that we added previously. This is done from the background Layer Properties window:

Background Layer Properties

The background layer is a layer that can be cleared to a single colour and/or have a single image applied to it. In this case we want to assign the dark tile sprite we added, so click on the section marked <no sprite> and select the sprite spr_darktile. You'll see that the image now appears in the top left corner of our room as a background, but that's not exactly what we want... we want it to tile across the screen. We could have created a tilemap layer for this and added the background as single tile, but with the background layer it's a lot simpler: just tick the Vertical tile and Horizontal Tile check-boxes:

Tile Background

Before continuing let's just look at a couple of the other options for backgrounds. You'll see that we have the option to Stretch the background image too. All this will do is stretch the background image used to fill the whole room area, which with a small image like the one we are using doesn't look right, which is why we tile it instead. You can also set the Horizontal Speed and Vertical Speed for the background layer. This will scroll the layer by the number of pixels given every game frame, so setting a horizontal speed of, for example, -2 will scroll the background from right to left at a rate of 2 pixels every game frame.

If you set this in the room editor you won't see anything happen, but in your game it will scroll. However sometimes you want to preview a change like this without having to compile the whole project to see how it looks, which is where the Animate feature of the room editor comes in very handy. In the main editor window, you have a bunch of tools in the top right corner:

Room Editor Tools

The one we are interested in here is the Play Animation button . Clicking this will animate the whole room such that any backgrounds that are set to move, or tile sets that are set to animate, or any sprite assets that have sub-images will be shown as they would appear in the game:

Animate Background

With the horizontal background speed now set to -2, this will add interest to our title screen, we can continue on to make our title object.


Adding The Title

To move from one room - the title room - to the next one - the game room - we will need a new object, so go ahead and make one now (Right click  on the object resource folder and select Create). Name this object "obj_title" and assign it the title sprite we created at the start of this section. Now add a Create Event:

The Title Object

We are going to have our object draw its sprite fading in gradually, just to create a slightly nicer looking title screen. To so this we need to use the built in variable image_alpha. All instances of objects have a number of built in variables that are related to how the assigned sprite will be drawn. In the Scoring Section we explained how GameMaker Studio 2 default draws the sprite assigned to an instance of an object, and most of the objects in this game have no Draw Event. However letting GameMaker Studio 2 default draw the sprite does not mean you cannot change how it is drawn, as you can using the different built in variables. These built in variables are changed using the different transform actions from the Instances library:

The Transform Instance Actions

You can change things like the scale, the rotation, the colour and the alpha, all through using these actions to change the built in variables. In this case we are going to change the alpha to make the sprite "invisible" at the start of the room. For this we add the Set Instance Alpha  action into the Create Event and set it to 0:

Set The Instance Alpha

We also want to make sure that the sprite will be drawn in the exact centre of the screen, so we need to add the Jump To Point  action, from the Movement library, like this:

Set The Instance To The Centre Of The Room

This action will set the instance to the position specified, and in this case we are using the global variables, room_width and room_height to get the middle of the room (half width and half height) for the instance when created.

Next we need to add a Step Event with the following actions:

Step Event Actions

All this action block is going to do is add a small amount to the image_alpha value and then check it to see if it is over 1, and if it is it resets it to 1. In this way we can ensure that the image alpha will increment until it reaches 1 and go no higher (this is important, as while you can set the image alpha value to more than 1 - or even negative numbers - this will have different effects on different platforms and the recommended value for this variable is always between 0 and 1).

We can now drop this object into the title room and test the game (open the room editor, click  on the object in the Resource Tree, then drag an instance of it into the room editor and release the mouse). You don't even have to worry about placing it properly because we've taken care of that in the Create Event of the object.

Room Introduction


Changing Rooms

The title text sprite says "Press Enter To Start", so we now need to have our instance detect that key and go to the next room to start the game. For that we need to add a Key Up Event

Key Up Event

The Key Up Event detects when a key has been released and won't trigger until that happens. We use this event just to give the user a moment to get ready to play, as the other two key events would change the room instantly. In this event we want to add a single action, the Room Goto Next action  (from the Rooms library):

Room Goto Next

There are a number of actions available for moving between rooms, but we only need this one since it simply goes to the next room in the Resource Tree, which is our game room. Care must be taken when using this action, though, as if there is no room after the current one (ie: the room using this code is the last one in the Resource Tree) we will get an error which will cause the game to close. Note that if we want to go to a specific room without following the order of the resource tree, then we would use:

Room Goto

The Room Goto  action lets us go to any room in the resource tree (you can press  to open the manual and see what all the other room actions are). If you run the game now, you'll get the title screen and pressing Enter will take you to the main game room to play. Note that because we already have the action Room Restart  in the player object when they die, then when the player dies the title screen will be shown again, so the player can prepare before each game after dying.


Summary

After completing this section we now have a nicer introduction to the game. While setting this up you should have learned the following:

  • How to add and re-order rooms in the resource tree
  • How to change the built-in properties (like image alpha) for drawing a sprite
  • How to use the keyboard events
  • How to change rooms using the Room actions
With that we are almost finished with this tutorial, but we have one final task before us. Currently the game has a limited number of enemies to destroy, which limits the gameplay greatly, so in the next section we'll look at "spawning" more enemies as you play...

Spawners

Game Room Setup

Our project is shaping up quite nicely, but we have one final thing to fix before we can really call it a game... Currently, if you destroy the enemies without getting hit, then the game doesn't do anything and the user has to close the game window. That's not very satisfactory for the player! So, in this section we are going to talk about "spawners", which will be controller objects designed to constantly spawn enemies.

NOTE: If you close the accompanying video then you can get it back by clicking here

Before continuing to add these spawner objects, we first of all need to remove the enemies that are currently in the room and prepare a new instance layer, so open the room "rm_game" now. In this room, we are going to create a new layer specifically for our enemy instances, so create a new layer now (click  on the New layer icon ) and name this layer EnemyLayer. Click  on the layer and drag it into the position between the Instances and BulletsLayer.

Add Enemy Layer

You can now select the Instances layer and then in the actual room editor workspace, use  /  +  to select all the enemy instances one at a time. Using  /  like this will group all the instances together so that you can do things with them like move or, as is the case here, delete them.

Select All Enemy Instances

With them all selected simply press the  key to delete them. Now we can go ahead and create our spawner object.


The Enemy Spawner

We need to create a new object for the spawner so do that now (click  on the Object resource folder and select Create), and name this object obj_enemyspawn. Assign the object the enemy sprite too (spr_enemy), as what we are going to do is make our enemies "grow" in size and then spawn, so that the player has a visual cue that the spawner is there and that an enemy is coming and they can move out of the way and prepare. Having an enemy just appear out of nowhere would be unfair and annoying to the player!

We now need to add the action  Set Instance Scale (from the Instances library) into the Create Event of the object. So add the event now and the action, with the following values:

Set Instance Scale Action

What we are doing is setting the built in variables for the assigned sprite scale to 10% of the base scale. GameMaker Studio 2 bases all the scale on factors, where a factor of 1 is 1:1 with the original sprite image, so a factor of 1.5 is 150% bigger and a factor of 0.5 would be 50% smaller. So, here we are setting the scaling factor to be 0.1 (10%) and then we are going to scale the image up to 1 (100%) before spawning the enemy.

To actually scale it up we need to use the Step Event, so add that now. We will use the same approach to scaling that we used previously for the image_alpha, so add the Set Instance Scale  action and then we'll do an If Variable...  check on it:

Scale Instance Relatively

This will scale up the image xscale and image yscale by 0.02 every game frame (note that the relative check-box is marked) and then it will check the value of the image_xscale variable to see if it is greater than 1 and if it is it sets the scale to 1. That's fine but we need to add one final action which we've not see before... The Change Object Instance  action. We'll use this to change the calling instance (the spawner) into an enemy instance, so drag that into the action list now and set it to change into the object obj_enemy, like this:

Change The Instance

So, first we check to see if the scale is 1 (100%) and if it is we change the instance into a version of the instance obj_enemy using the action Change Object Instance .

With that done, you can go back to the game room and on the new EnemyLayer layer add five or six instances of the object (click  on the obj_enemyspawn object in the resource tree and then drag it into the editor window and release the mouse button). When ready, click the Play button undefined to test your game and you should see that the enemies now scale into existence.

Enemies Scale Into Existence


The Spawn Controller

We have our enemy spawn object now, but we don't have anything to re-spawn the enemies when there are none left, so for that we are going to create a controller object called obj_spawner. Go ahead and create a new object now and give it that name. You don't need to assign a sprite to it, but you will need to open up the Create Event. We are going to use alarms in this object to create instances of our enemy spawn object within the room, so to start with add the following Actions into the Create Event:

Create Spawn Timer

The first action sets a variable to control the speed at which enemies will spawn. The next action sets the alarm [0] to the value of spawn_rate. But what are alarms? They are special events that will count down every game frame until they reach 0, at which time they will perform the action code added into the event in the object. So, in our actions we are setting the alarm[0] to 60, meaning that it will subtract 1 from 60 every game frame until it reaches 0 at which point any code in the alarm[0] event will run. You have 12 alarm events and they can also be accessed using the built in variable array alarm[0 .. 11].

NOTE: An alarm does not stop on 0, but will actually count down to -1. So the event runs when the alarm reaches 0 and then subtracts one more from the alarm to get to -1. This is useful to know as it means you check to see if an alarm has run or not by checking to see if it is less than 0.

You need to add the corresponding alarm event now, so since we are using alarm[0] you need to add Alarm Event 0:

Alarm Event 0

This event will only trigger when the alarm[0] array has counted down to 0 and in it we want to add the following:

Reset Spawn TImer

Here we are creating an enemy spawn object at a random position within the room and on the layer we created at the start of this section. We then reset the alarm to the spawn_rate value so that it will count down again and spawn another one. In this way, every 60 frames a new enemy will be created for the player to shoot at.

You can close this object now and go back to the game room. We had added in enemy spawn objects but we don't need them anymore so select them and delete them ( /  +  to select, and  to delete). Now drag an instance of the controller object obj_spawner into the room and run the game.

Enemies Spawning In Game


Summary

After completing this section we now have a pretty much complete, albeit basic, game. Adding the spawner objects has made the gameplay more dynamic and enables the user to play again and again and try to beat their own highscores. Let's quickly run through what you should have learned from this section:

  • How to select multiple assets placed in a room
  • How to use image_xscale and image_yscale to change the scale of a sprite
  • How to use instance_change to switch objects
  • How to use an alarm in a controller to create timed events

With that, this tutorial is pretty much finished. We have covered all the basics that you need to know to get yourself started making games, and we've given you a base game to work on and try to change or add to. Things to consider adding to this project would be:

  • A game over screen
  • A high score feature where the highest score ever is saved and shown to the user
  • Enemies that shoot at you
  • Background music and better/more sound effects

The list could go on and on, but it's entirely up to you what you do from now on. GameMaker Studio 2 has given you the tools, so use them to the make the games that you have always wanted to make.