Intermediate Topics of GameMaker

GM Version: GMS1 (Please let me know whether code is compatible with GMS2 or not in the comments.)
Target Platform: Generic (All Platforms)
Download: N/A
Links: N/A
Author: BW3 (Legacy Forum)

Summary:
"Over the 8 years of experience I have had with GameMaker, I’ve spent a majority of my time in various questions and answers boards. Through my time spent doing this, I’ve noticed that a solid majority of GameMaker users ability plateaus after learning the basics of GML coding, but not what to do next. They learn the basics of programming, setting variables, using events, even a couple lesser used functions, but they never really have the roots to learn what GameMaker has the potential to do.

For this guide, I am going to assume that you have a basic understanding of GML syntax. If you have not progressed this far, a great way to start is by converting DnD to GML and learning the equivalent code. This will be broken up in to multiple sections. This post will be more programming based, and learning how to program. The rest of the posts will cover specific tools available in GameMaker, and how to use GameMaker to it’s maximum functionality.

I would strongly suggest having the manual for GameMaker open and available while reading this."

Topics:
  1. Terms
  2. Loops
  3. With Statements
  4. Arrays
  5. Scripts
  6. Trigonometry and Algebra

Terms
This is a list of terms and meanings that will be used throughout this guide
  • Expression: An expression is in essence code that doesn’t do anything. It’s used as checks for if statements and loops. Comparing things is the biggest example of this, as well as checks like place_free().
  • Statements: Code that does something. Whether it’s x=64, calling a draw_ function, or changing rooms. This includes functions like move_towards_point()
  • Argument: This is an input to a function or script. It can be a variable or number.
  • Return: The “answer” to a function, or what a function or script outputs.
Loops
The first topic I noticed that people seem terrified of is the idea of loops. There are three types of loops available in GameMaker.
  • Do/Until
  • While
  • For
Each of these have a slightly different use, but can be used interchangeably with the right formatting. The basic idea behind a loop is that it is something that can be done more than once per event.

Do/Until
The Do/Until expression is the simplest loop to learn about.

Code:
do <statement> until (<expression>)
What this means is that GameMaker will DO the statement UNTIL the expression is true. To use the manuals example

Code:
//This will randomly place the object until it is in a free spot

do

{

x = random(room_width);

    y = random(room_height);

}

until (place_free(x, y))
In simpler terms, the until part of the code acts as an if statement. The do function will continue to run until the expression is true.

While
The while expression is similar to the do/until expression in that it keeps running until an expression is false. Here’s what the manual looks like:

Code:
while (<expression>)

{

    <statement>

}
To reuse the example from above

Code:
while(!place_free(x, y)) //The ‘!’ means not, or opposite

{

    x = random(room_width);

    y = random(room_height);

}
This code does the same as above, albeit a little differently. While loops are generally prefered more than the do/until expression. The argument of the while statement acts as an if expression. If the expression is true, then it continues to run through the code inside the statement. The main difference between a while loop and a do/until loop is that

For
The for loop looks a little more advanced than these other two, however it is not much different. For loops are different from while and until loops as instead of just waiting for an expression to become true, they change a specific variable until the expression becomes true. For the purposes of this, I’m going to call that variable the looping variable, and in code it is the letter ‘i’. This is useful if you want to loop through code a specific number of times, whether that number is set or a variable. Here’s what the manual says about for loops:

Code:
for (<statement1> ; <expression> ;<statement2>) 

{

<statement3>

}
At a glance, this looks difficult. However, I’m going to break apart what part of that is.

  • statement1: This is the initial value of the variable going to be looped through. Normally i, j, and k are used for these.

  • expression: This is the expression that the loop will stop at when reached. This must be a compare between the looping variable and an expression or number.

  • statement2: This is how you are changing the looping variable. This can only been done here, and the looping variable cannot be changed inside the code.

  • statement3: This is the code running inside the for loop. It doesn’t need to reference the looping variable, but can.
As an example, I’ll show you how to draw a number of hearts using the for loop and the looping variable i.

Code:
for(i=1; i<=hearts; i+=1)

{

    draw_sprite(heart_spr, 0, 64+32*i, 32);

}
This will draw the number of hearts equal to the variable, 32 pixels apart.

This is what the same code would look like in a do/until loop

Code:
i=1;

do

{

    draw_sprite(heart_spr, 0, 64+32*i, 32);

    i+=1;

}

until (i>hearts)
Here’s what a snippet for platformer landing would look like:

Code:
ystarting = y;

for (i=0; i<=vspeed; i+=1)

{

    if place_free(x, ystarting+i)

    {

        y = ystarting+i;

        vspeed = 0;

        gravity = 0;

    }

    else

    {

        break; //This exits the loop early

    }

}
This will increase i as long as the place for the object to go is free, and exits the loop as soon as it isn’t. This means that you have a pixel perfect landing every time.

Summary
Loops have an incredible number of uses in programming, and are one of the most powerful tools available to you. They can be used if you want to do something a number of times, or want to do something until an expression is reached. They are a relatively easy core concept of programming and are a necessary part of a lot of coding. They come with the break and continue commands, and I would suggest reading over those in the GameMaker manual.

With()
The with() statement allows you to run code on other objects and instances from events in an object. Inside of a collision event, with(other) runs code on the object being collided with. It is the same as selecting the other or selecting an object in the drag and drop buttons, or at the top of the code window.

Here’s a basic example of how to use it to turn all the balls in a room red.

Code:
with(obj_ball)

{

    image_blend = c_red;

}
Here’s an example of how to use a with statement to set the speed and direction of a bullet.

Code:
var ID;

ID = instance_create(x, y, obj_bullet);

ID.creator = id;

with(ID)

{

    direction = creator.direction;

    speed = 8;

}
You can also run code in a newly created object directly.

Code:
with(instance_create(x, y, obj_ball))

{

    speed = 8;

    direction = random(360);

}

Arrays
Arrays are another topic that are fairly simple, but many new users are afraid to use. At it’s core, an array is a table of values. The location of the value is called the index. This is what it looks like:

Array[index] = value;

To set an array, you just use the index, and set it to a value.

Code:
X_v[0] = 10;

X_v[1] = 20;

X_v[2] = 30;

Y_v[0] = 16;

Y_v[1] = 32;

Y_v[2] = 64;
Here’s what that would look like laid out on a table.

Code:
X_v      Y_v

10        16

20        32

30        64
Now, let’s use that along with a for loop to spawn some objects.

Code:
for (i=0; i<array_length_1d(X_v), i+=1)

{

    instance_create(X_v[i], Y_v[i], obj_ball);

}

Now, arrays can be one dimensional, or two. It’s best to think of them as just a table of values. I’m using the same example as above, just using a 2D array. The first input(row) is the number it is, the second(column) is the x and y.

Code:
P_v[0, 0] = 10;

P_v[0, 1] = 16;

P_v[1, 0] = 20;

P_v[1, 1] = 32;

P_v[2, 0] = 30;

P_v[3, 0] = 64;

for (i=0; i<array_height_2d(X_v), i+=1)

{

    instance_create(P_v[i, 0], P_v[i, 1], obj_ball);

}
This is what P_v would look like laid out on a table.

Code:
10      20       30

16      32       64
Note that you can use two for loops inside of each other(one for length and one more height) to go through all the values in an array. See the example in the GameMaker manual under array_height_2d(). Any time you need a table or list of values, or a chart(such as one in excel), you can use arrays. If you need more advanced functions to work on arrays, such as sorting them, I would use the more advanced data structure functions, prefixed with ds_. I’ll cover those in a separate post at a later date.


Scripts
Scripts are basically homemade functions. Things that you want different objects to do, or code that is often called on in different places. They act as functions throughout the code, and can be used any way functions are. If they return a value, they can be added to if statements. When making a script, there are a couple things you need to know.

Arguments are an important part of making a script. These are your inputs, and should be used for any variables the script is going to need. The second thing to use is the return statement. This is what your script will return, for example if you are using them in an if statement or want the script to set a variable for something. As an example, let’s make a script called path_clear(). It’s goal will be to check if there is anything in the objects path between two point. It will have 4 input arguments, x_start, y_start, x_end, and y_end.

Code:
//When using scripts, make sure to declare var and all the variables at the beginning

//This will remove any issues with common names later. 

var x_start, y_start, x_end, y_end, x_point, y_point, distance, i; 

//This script checks to make sure nothing is in the path between the start and end points

x_start = argument0; //This sets your inputs to the correct variables

y_start = argument1;

x_end = argument2;

y_end = argument3;

distance = point_distance(x_start, y_start, x_end, y_end);

for (i=0; i<=distance; i+=1)

{

    if !place_free(x_start+(x_start-x_end)*i/distance, y_start+(y_start-y_end)*i/distance)

    {

        return 0; //Returns automatically end a script

    }

}

return 1;//The code will never reach this point if any of the places are not free
Now, to put this in the code somewhere.

Code:
if path_clear(x, y, enemy_obj.x, enemy_obj.y)

{

    move_towards_point(enemy_obj.x, enemy_obj.y);

}
Scripts can be used anywhere a function can, including as part of an if statement, inside loops, and inside with statements for other objects. Just make sure that you use var to declare all of the variables in your script, because otherwise these might interfere with variables on the object.

Trigonometry and Algebra
Now, a basic understanding of algebra and trigonometry is extremely important in GameMaker. However, GM allows you to avoid having to use the actually trigonometry functions to do most of the things that those would allow you to do. There are a couple functions in GM that allow you to use your standard cartesian(grid) coordinates to do most of the things that trigonometry is useful for.

These are:

  • point_distance(x1, y1, x2, y1);

  • point_direction(x1, y1, x2, y1);

  • lengthdir_x(len, dir)

  • lengthdir_y(len, dir)
From these, you can get everything you need out of the basic functions of trig without having to do any of the math yourself. Granted, actually knowing this math is helpful, but not entirely necessary. If you are interested Khan Academy offers free online courses on the basics of trigonometry, and odds are if you took it in high school, it will probably come rushing back to you.

Now, point_distance and point_direction are fairly self explanatory. They return the distance to and direction to a point from another point, respectively. However, the lengthdir functions are cause for a lot more confusion.

Simply put, the lengthdir functions return the x and y values of a given distance and angle. Behind the scenes, they use trigonometry to find these values, however GameMaker makes them easy. For an example, say you want to move an object 8 pixels towards another object. You can use lengthdir to move it in the proper direction an exact length of pixels.

Code:
dir = point_direction(x, y, enemy.x, enemy.y)

x = x+lengthdir_x(8, dir);

y = y+lengthdir_y(8, dir);
This will shift it 8 pixels in the given direction. Now, if it’s within 8 pixels of the target, it will overshoot it. How to avoid that? Go a smaller distance if the distance is shorter. This can be accomplished easily using the min() function, which returns the minimum of the given values.

Code:
dir = point_direction(x, y, enemy.x, enemy.y)

dist = point_distance(x, y, enemy.x, enemy.y)

x = x+lengthdir_x(min(dist, 8), dir);

y = y+lengthdir_y(min(dist, 8), dir);
If the distance is greater than 8, it will move 8. If the distance is less than 8, it will move that distance. It’s important to remember that distances can’t be negative, and the standard directions are used for all outputs and inputs. No need to convert to and from radians, unlike the standard trig functions.


As far as algebra goes, remember that Gamemaker can do most of your mathematics for you. No need to figure a lot of things out on paper if you can just type all the equations into GM and have it calculate them in real time. Speaking of equations, you can just toss those in to things and see what happens.

Let’s say you want to have something slowly fade out, but not linearly.

image_alpha*=0.8 is a great way to set that effect up. This, over time, creates an exponentially decreasing curve. The same equation can be used for the time between a gatling guns shots, how quickly a radius grows for an effect, or slowing something down. It’s a smoother transition than just decreasing the value, and allows for it to go on infinitely if needed. Plugging in random equations to things is always a great way to create lots of cool things, even if they do take a lot of adjustment. Things like the sin() function create cool effects, especially if you need a wave, or something that alternates between -1 and 1. Here’s a little snippet based on drawing hearts, except in a pattern.

Code:
for (i=1; i<=hearts; i+=1)

{

    draw_sprite(heart_spr, 0, x+8*cos(pi*i), y+i*8);

}
If you plug this in, you’ll see how the hearts go up and down in two neat rows.

Once again, Khan Academy is a great resource for learning or refreshing your basic algebra concepts.


Afterwards
Now that you have the basics of GameMaker programming, you can learn pretty much anything. Look around the reference section of the manual. There are tons of useful tools in there that you may have never heard of. GameMaker is there to make creating games easy, so why not use all of it? You can also learn lots of information really quickly by just looking at the answers to select questions, such as the GameMaker Community’s Programming Board.
 

chance

predictably random
Forum Staff
Moderator
Normally, we ask that tutorials focus on one concept at a time. Or contain one concept per "update", like some ongoing tutorials series posted here. But this contains a few closely related examples, and it could be helpful.

That said, some areas could be improved.

-- The discussion of lengthdir_x and lengthdir_y doesn't properly explain the concept of x and y "components" of a distance. And it would also benefit from a diagram. In this case, the GML manual does a better job.

-- The section on the FOR loop is OK. But your example introduces the ELSE construct without any prior explanation.

-- One of the WITH examples introduces the "dot" construct and it also uses the calling object's id without much explanation.

-- The ARRAY example uses the array_length_1d(array) function without explanation, other than a later reference to the GML manual for 2D arrays.​

Just some suggestions to think about updating.
 
Normally, we ask that tutorials focus on one concept at a time. Or contain one concept per "update", like some ongoing tutorials series posted here. But this contains a few closely related examples, and it could be helpful.

That said, some areas could be improved.

-- The discussion of lengthdir_x and lengthdir_y doesn't properly explain the concept of x and y "components" of a distance. And it would also benefit from a diagram. In this case, the GML manual does a better job.

-- The section on the FOR loop is OK. But your example introduces the ELSE construct without any prior explanation.

-- One of the WITH examples introduces the "dot" construct and it also uses the calling object's id without much explanation.

-- The ARRAY example uses the array_length_1d(array) function without explanation, other than a later reference to the GML manual for 2D arrays.​

Just some suggestions to think about updating.
Thank you for your thoughtful suggestions, @chance. I'll start drafting an update later today. :)
 
Top