Skip to content

Programming Tips

Austin Frey edited this page Feb 1, 2020 · 1 revision

Welcome to Dust: Fire and Ice! If you're interested in programming, but have no experience with GML or programming in general, you're in the right place! Here we'll be doing a quick rundown of how to program in GML with a few tutorials along the way to help you out. Our goal is to teach you the basics, so you can begin to tackle beginner issues listed on the issues tab for practice. Throughout the tutorial you can hover over images to get a little more information about them. Let's dive right in!

Contents

GameMaker Studio 2

Upper Level Organization

Data Types

Data Structures

Variable Assignment

Logical Operators

Events

Loops

Creating Resources

The First Tutorial (Player Movement)

Tutorial Part 2

GameMaker Studio 2

Let's start at the very beginning. GML stands for Game Maker Language, the coding language for GameMaker Studio 2 (GMS 2). Don't have GMS 2? Download it here. GameMaker Studio 2 is an IDE or Integrated Development Environment. That's just the place where you code. It helps you organize your code and, in GameMaker's case, will do lots of the tricky upper level coding for you. What upper level?

Upper Level Organization

GMS 2 has different resources for you to use, these are specially made to make game making easier. The resources are as follows:

  • Sprites - The images that make up your game, the player, the enemies, walls, coins, etc.

sprite screen

  • Objects - Where you'll be coding most. The objects are the things you'll be telling to do stuff. Like the player. Most objects will be assigned a sprite so the player can see them in the actual game. If you're confused about how our objects are organized, visit the object tree for more information.

object sceen

  • Scripts - Functions or modules in other coding languages. These are just bits of code you want to use a lot. They usually take in some inputs, do something with them, and then give an output. Lots more on these later.

script screen

  • Rooms - Where the game takes place, the 'screen' the player will see. The room here is shown on the right with a grid, some information about what's in the room is on the left.

room screen

As a quick rundown then, you might create an object, such as the player, assign it a sprite (a little person perhaps), give the object some code and maybe have it run a few scripts that tell it to move when a key is pressed. Finally you might place that object in a room so it has some place to move around in. Voila! You have a little game!

There are more resources than this, but these are the ones you'll be using most as a beginner. Next we'll talk about the language basics.

Data Types

GML, like all coding languages, has many different things you can assign to variables. Some of these are:

Type Example(s) Explanation
Numbers 0 2.45 -1000 All numbers, integers, decimals, positive, and negative
Strings "Hello" " " "What is up?" Anything in quotation marks (single quotes or double)
Booleans true false Just true or false

You might have noticed the array can contain all sorts of other types in it, it just groups them together so you can call them later.

Data Structures

GML also has 'structures' for organizing and storing information. In general, these structures store information (such as variables or values) in different indexes that can be called later. Essentially they are just variables with lots of different values stored in them. Here are the different data structures:

Name Storing Method Release method Create Accessor Destory
Stack 'vertical list' Last item in is the first item out (LIFO) ds_stack_create() N.A. ds_stack_destroy
Queue 'horizontal list First item in is the first item out (FIFO) ds_queue_create() N.A. ds_queue_destroy
List 1-D array Accessed by index ds_list_create() | ds_list_destroy
Maps Keyword-value pairs Accessed by keyword ds_map_create() ? ds_map_destroy()
Grid 2-D array Accessed by two indices ds_grid_create() # ds_grid_destroy()

The data structures can be created with the create function e.g. my_list = ds_list_create(), filled and called with the accessor e.g. my_list[| 2] = 5 or value = my_list[| 2], and destroyed with the destroy function when finished using it e.g. ds_list_destroy(my_list). Destroying lists save memory space and prevents memory leaks that could slow down a game. There are many other functions that can be used with data structures which are listed on GameMaker's help page.

Variable assignment

Hopefully you know what a variable is; a symbol that represents something else. In our case it could represent any of the data types above. How do you assign a value to a variable? Very easy:

lives = 5

Ta-da! The object I typed this in now has 5 lives! Of course this doesn't mean anything until we make it lose lives and die when it runs out of lives, but its a start. Watch, I'll do it again.

player_name = "Bobby"

I just assigned a variable called player_name a string with the value of "Bobby". Variables can be assigned any data type, not just numbers!

Alright, hopefully you get the gist. You may have noticed my variables are always lower case and one word. There's a reason for that and you can learn about it on the CONTRIBUTING page under Coding Standards and Style Guide. That'll be important before you start contributing to actual issues, but it isn't a big deal right now.

Okay, back to the first example lives = 5. I said it didn't matter if the player had lives if he couldn't lose them. Let's try using an operator to change the variable. Some operators are:

Operator Purpose
+ Add
- Subtract
* Multiply
/ Divide
= Set equal to

So say we want to use - to get rid of a life. We type:

lives = lives - 1

Wait, why not just lives - 1? This will give you a result of 4, but the problem is that 4 does not belong to the variable lives. If we want lives to change we have to assign the new value (lives - 1) to the variable lives. Now if we were to check the value of lives it would give us 4.

Side note: this is a little clunky, when we are changing the value of a variable we can use a little shortcut to set a variable equal to itself - 1. Instead of lives = lives - 1 we could type lives -= 1 which means set lives equal to itself - 1. This works with the other operators too +=, *=, and /=.

Cool! The player lost a life. But now we want the player to die if he is all out of lives. To do that we need logical operators and our first control statement: the if statement.

Logical Operators

Logical operators are one of the most commonly used things in coding. You've seen them before in math plenty of times, they are:

Logical Operator Purpose
< Less than
> Greater than
== Equal to
!= Not equal to
<= Less than or equal to
>= Greater than or equal to

These operators are often used in an if statement. This just says if a condition is met, then do the things I include in braces {}. They look like this:

if condition{
    Do Thing
}

Let's try it with our lives problem. We want the player to die (or disappear) if they have less than one life. So we use:

if lives < 1{
    instance_destroy()
}

The variable lives being less than 1 is the condition, destroying the instance (deleting the player from the room) is the action. Let's say we want to try it different way and destroy the player when the lives are equal to 0. How would you do it? Click to see the answer.

Answer

if lives == 0{
    instance_destroy()
}

Did you remember to use == for checking to see if two values are equal? Did you remember the braces?

Okay here's another one. Let's say you have defined a variable speed and another variable max_speed. You want to check if speed is greater than max_speed. If it you want to set speed to be equal to max_speed. Essentially this is an upper speed limit for your character. So what do you type?

Answer

if speed > max_speed{
    speed = max_speed
}

Don't forget = when setting a variable, == when comparing.

A quick but important note. Sometimes you'll want to do something if the condition is not true. To do that use an else statement. That looks like this:

if speed < 5{
    speed += 1
}
else{
    speed = 5
}

This code will increase the speed to 5 if it's less than 5 else it will set the speed to 5.

These examples have all been comparing a variable to a number, but you could check a boolean (true or false) value. For example:

if is_alive{
    score += 1
}

Here is_alive is a boolean value that could be either true or false.

Good. That's a good portion of beginner programming. Now let's figure out where you're typing this code at.

Events

Events are contained in objects. Typically the event tells the object when to execute that code. Here is the event list in GMS 2:

Event Screen

Each event provides an editor for the programmer to type code in that appears to the right of the object editor. It looks like this:

Event Editor

The events have the following function:

Event When the code is performed
Create When the object (or instance) is created)
Destroy When the object (or instance) is destroyed
Clean up At the room end or game end
Step Constantly. Specifically at every "step" (each step is usually 1/30th of a second)
Alarm When the alarm goes off
Draw At every step, but made specially for draw functions
Mouse When a specified mouse button is clicked
Key down Every step the specified key is held down
Key pressed Once every time the specified key is pressed
Key up Once every time the specified key is released
Gesture Whenever a specified gesture is done
Collision When a specified object collides with another specified object
Other Some other times code can be performed
Asynchronous Some other special times code can be performed

Phew. This seems like a lot but the events are pretty self-explanatory and which to use will come naturally with some practice. The important thing to remember is this is where you will be typing a code for a specific object. The event is when it happens, the code you type is what will happen.

Now let's try a little test. If you made an object, we'll say its called obj_player and we want to set its lives to 5 at the beginning of the game, where do we do this? That is, in which event? The create event. Since the objects placed in a room are "created" at the beginning of the game, all their create code will run when the room starts (typically when the game begins).

Okay, your turn, where do we type our code if we want to check if the player is dead? That is if lives < 1. Say the player could die at any time.

Answer

The step event. When do we need to check if the player is dead? All the time. So we use the step event to run the life check constantly.

Loops

One more topic to cover before you can really start programming. Loops are what makes computers so great. With these loops we can perform code over and over a certain number of times or until a certain event occurs. There are two main loops for loops and while loops.

For Loops

For loops perform code for a certain number of times. They are set up a little strangely, but not too complex. Here's an example.

var i
for i=0; i<10; i+=1{
    count += 1
}

What does this mean? Let's break it down. First line var i. This is just declaring a counter variable to keep track of how many times the loop has run. The var means this variable only exists in this event, so we use i in another event. Next: for i=0;. This sets i to 0, just like a normal variable assignment. i<10; This is essentially an if statement. It says it will run the code in the loop if i < 10. i+=1 This final section says what to do to the variable i at the end of the loop. In this case, i will increase by 1 or increment.

So how many times will this loop run? i starts at 0, increases by 1, and runs until i is no longer less than 10. So it runs when i is 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. So 10 times in total. The loop adds one to the count variable. So if the count variable starts at 0 it would end at 10 when the for loop finished. Of course you could just set count = 10 so let's look at a more practical example:

var i
for (i=0; i<5; i+=1){
    create_instance_layer(16 * i, 16 * i, "Instances", obj_wall)
}

Okay, so we can see this loop is going to run 5 times, from when i = 0 to when i = 4. What does it do? The instance_create_layer() function places an object in the room at a certain (x,y) coordinate. The x and y coordinate given here are both 16 * i. i changes each time the loop is run. So this loop will create an obj_wall at (0,0); (16,16); (32,32); (48,48); and (60,60) in the room.

For Loop Example

Your turn. Write a for loop that will run 8 times but initialize i as i = 8. Each time the loop runs multiply a variable called big_number by 5 and set big_number to that new value.

Answer

var i
for (i=8; i>0; i-=1){
    big_number *= 5
}

Hopefully you got that, if not, you can learn read more here.

While Loops

while loops are more uncommon in GameMaker since they specify a certain time code should be executed, which, if you recall, is also what events do. The danger is including a loop that runs infinitely which would freeze the game. Still they are useful sometimes. The syntax is like this:

while (i > 10){
    i -= 1
}

This while loop is basically a for loop. As long as the i is greater than 10, it will be reduced by 1 until it reaches 10.

Creating resources

Creating resources is simple. The right side of GameMaker Studio lists all the resources. Simply right click on a resource and select Create. For example, to make an object, right click on objects and hit create.

Object Create

The same can be done for sprites, scripts, rooms, etc.

The First Tutorial

You now have enough knowledge I can show you how to complete a simple task from start to finish. This is not just practice, they'll be explanations on lots of functions and coding that we haven't covered yet. Here is the task: Make a game with a player that can move in 4 directions (2-D) with the arrow keys. Here are the steps:

  • Create a new project
  • Create a player sprite
  • Create a player object
  • Add events to the player for each of the 4 arrow keys
  • Code the events to set the speed for the player
  • Create a room to move around in
  • Place the player object in the room
  • Test the game

Okay, let's go. Open GameMaker Studio 2. Go to File>New Project. Create a player sprite, remember that is done by right clicking on the sprite resource and hitting create. You should have a screen that looks like this:

Sprite Creation

Change the name of the sprite to spr_player. spr standing for sprite of course, player being the name of the sprite. We'll leave the size as 64X64 to make things easy. Hit edit image. The sprite editor runs pretty much like an MS Paint program or something of the like. Use the paintbrushes, drag circles or rectangles, change colors. You can read more about the editor here if you want to go more in depth. I just made my player a circle, like this:

Player Sprite

Easy peasy.

You can exit out of those, they'll save automatically. Next create an object and call it obj_player. Also set the sprite of the object to be spr_player, the sprite we just made.

Player object

Great. Now you can see the add event button. You'll recall we need some place to put our code, and that will be in these events. We ask ourselves when we want our code to be executed. In this case, the answer is whenever the user hits any of the arrow keys. Specifically, whenever they are holding down on the key. It makes sense that we use the key down event for this. If that doesn't make sense click here.

We'll start with key down> left. Change the text following the @description to be Move left so we know what this event is doing. How do we make the player go left? We can set its hspeed a built-in variable controlling how many pixels the object moves horizontally each step. Let's say we want it to go 5 pixels each step. We'll type hspeed = -5. Why negative? Here's why:

Directions

So since we want to go left we need to move in the negative x direction. Our code should look like this:

First Event

How about the rest? As you can guess, we just repeat for right using hspeed = 5. The same is done for up and down but using vspeed for vertical speed instead of hspeed. Once we're done with that we need one more thing. Making the player stop. To do this we use a different event key up> any which runs the code whenever any key is released. In here we just set hspeed = 0 and vspeed = 0 to make the player stop. Your object should look like this:

Completed movement

And you're done! Well almost. All you have to do now is create a room, like you did the object and sprite. Then drag the object from the right side into the room. If it doesn't work make sure you have the "Instances" layer selected on the right side.

Room

Now you're ready, hit F5 or the run arrow in the top middle of the screen to run it. Can you move? Does it stop? If so, congrats! If not read the tutorial again and see where you went south.

Tutorial Part 2

Okay, the first part was fairly easy. Now things are going to get a little trickier. We are going to continue our tutorial in the same game, but now we are going to make the player shoot a bullet the direction the player is facing whenever the space bar is pressed. To make it even harder, the bullet sprite won't be a circle, so we'll have to make it point the direction the player is moving! Let's get started!

What we need to do:

  • Create bullet sprite(s) pointing all 8 directions
  • Create bullet object
  • Type creation code for bullet into a space bar event
  • Make the bullet move the direction the player is moving
  • More stuff you'll see as we go

Alright, first create the bullet sprite, you will get good at making sprites pretty quickly. This sprite we'll call spr_bullet remembering to always include the suffix spr_ so we know it's a sprite. The bullet aught to be smaller than the person so let's change the canvas size to 16X16, on the left. If you wanted to stretch a sprite you already made, you would scale the image.

Size

Good. Now let's make a bullet pointing right. My bullet is simple enough but points a definite right, which is what we want here.

Bullet 1 frame

Great! Now as long as we only fire right we'll be good to go. Unfortunately we should play it safe and make a few more directions. To do this, we'll be adding new frames to this sprite. You can do this by clicking:

Add frame.

That button. Now to rotate the sprite, we can just select it using the rectangle select tool on the left, copy it, go to the new frame, and then use the rotate brush tool. Rotate it 45 degrees, click on the pencil again and carefully place it. Okay, now do that 6 more times until you have all 8 directions. I recommend rotating the first bullet 8 times instead of one after the other so it doesn't get too blurry. Now your sprite should look like this.

All frames

Bullet sprite done. Now make a bullet object called obj_bullet and set the sprite to be spr_bullet. I trust you can handle that so no picture for you. Now try placing a obj_bullet in the room and hit play. A few problems here.

  1. Our bullet is black and the room is black, so you can't see it
  2. The bullet is spinning

Solution to 1. is to change the background color of the room. You might have to go to room>layer properties, or hit ctrl-alt-p to see the window below.I made my background a nice grey.

Background color

Solution to 2. is to add a line of code to set the image_speed = 0. The image_speed is how fast the sprite cycles through its frames. Where will we put this code if we want it to happen right away? The Create event! Here we go.

Bullet Image Speed

Hopefully you noticed that image_speed turned a light green. This is called syntax highlighting. All built-in variables in GMS 2 will highlight green so you know GameMaker already has a purpose for that variable and not to make your own variable that same name.

Now that our bullet is no longer spinning, it's time to get the player to create the bullet, instead of placing it in the room. No worries, the Create code we wrote will still work, it will just run when the player creates the bullet instead of when the room creates the bullet.

Our bullet creation is happening in the Key pressed>Space event of the obj_player since the player is creating the bullet. We'll use the built-in instance_create_layer() function we used once before which accepts (and requires) four parameters. These are the x and y coordinates to create the object at, the layer which is kind of the third dimension for the object, and finally the name of the object to create. Our function will look like this:

instance_create_layer(x, y, "Instances", obj_bullet)

The x and y means the obj_player's current x and y. Play the game and make sure your character can create bullets with the space bar.

You'll notice the bullets create in the top left corner, that's because the (0,0) coordinate for objects are in the top left. To fix make the bullet create in the middle, we'll just add 32 (half the player size) to the x and y coordinate.

instance_create_layer(x + 32, y + 32, "Instances", obj_bullet)

Now let's make the bullets move. This is a little tricky. We need a new statement, the with statement.

The With Statement

with is a special keyword in GameMaker that essentially moves the code over to a different object. If you say in obj_player:

with (obj_bullet){
    x = 5
    y = 5
}

That will set the bullets x and y coordinates to 5, not the player's, even though this is occurring in the obj_player. This is because the with statement makes obj_bullet the owner of that code. This is useful when you want to refer to a specific instance of an object, that is just one bullet instead of all bullets. Place the with statement in front of the creation code and voila! you've got code that applies to just one instance of the bullet instead of all of them.


Okay back to it. We'll apply this magic to our code to get with instance_create_layer(x + 32, y + 32, "Instances", obj_bullet){. Now what do we want to change about this particular obj_bullet`? Well we want it to point the direction the player is moving. To do this we need to know which direction the player is moving (or last moved). Let's go over to our movement events to change this.

First though I have a confession to make: I told you a crappy way to get the player to stop. I'm sorry.

We made it so when the user releases any key the player will stop. But now we're using the space bar! Do we want the player to stop whenever we release the space bar? No. Let's change this. We'll make it whenever the arrow keys are released they stop moving the direction the arrow key was moving them. As such:

New movement

So our left and right Key up events set hspeed = 0 and our up and down Key up events set the vspeed = 0. Disaster averted. As you code more, your foresight for these issues will get better.

Back to the movement events. In the Key down>Left event, let's set a variable to tell us the player is pointing left: xdir = -1. Let's do the same for right, up, and down with xdir = 1, ydir = -1, and ydir = 1. We'll also set xdir to 0 when we release left and right and ydir to 0 when we release up and down. Now we know which direction the player is pointing at all times.

So back to our with statement.

with instance_create_layer(x + 32, y + 32, "Instances", obj_bullet){
    image_index = ???
}

image_index is which of the bullet sprites we'll be using. 0 is right, 1 is right and downward, 2 is downward, and so on. To get it to create the right sprite we need to associate the values xdir and ydir with the values 0-7. There's a few ways to do this but we'll use a script for practice. Create a script, rename it scr_find_direction and set it up like this:

Script

Sorry for all that typing but I hate to tell you that's not a huge script (although it is hugely inefficient). Now we can finish our with statement. All this does is return the correct image index depending on the xdir and ydir.

Shooting

Let's look at this. First we set the image_index to our function we wrote. We have to specify obj_player.xdir and objplayer.ydir because the with statement means this code is executed by the obj_bullet. You could also use the other keyword. Same for setting the bullets hspeed and vspeed. Now we have bullets that create pointing and moving in the right direction! Test it out. It's not perfect because we handled the direction setting for the player kind of shoddily, but it still works.

Quite a few problems still.

  1. When you're not moving the bullets don't move
  2. The bullets are never destroyed, so if you play long enough they will slow down the game

However I'm going to call that enough for this tutorial. We covered a lot. Did you understand it all? If not, it's okay, do some research, figure things out. Keep coding!