The GameMaker Language (GML) has a number of features which are part of the essential structure of all code written with the language. Each of these will be used in any code you write multiple times, so you should know what they are and how they work before getting started with programming a project.
A simple if statement takes this form:
if (<expression>) <statement>
or it can have the slightly more complex "if... else..." form:
if (<expression>) <statement> else <statement>
In this case the expression will be evaluated, and if the (rounded) value is < = 0 (false) the statement after else is executed, otherwise (true) the other statement is executed. It is a good habit to always put curly brackets around the statements in the if", and take a new line in the block for each statement, so the end code will have this form:
if (<expression>)
{
<statement>
...
<statement>
}
else
{
<statement>
}As a small example, consider the following code which will move the instance towards the position x=200 in the room:
if (x < 200)
{
x += 4;
}
else
{
x -= 4;
}Note that you can also do compound checks in an if, ie: check various values or expressions in the same statement. When you do this, GameMaker Studio 2 will evaluate each of them one at a time, and if any one of them evaluates to false, then the rest will be skipped. For example:
if (keyboard_check_pressed(vk_enter) && !instance_exists(obj_Player))
{
go = false
alarm[0] = room_speed
}You can also perform conditional operations (also know as ternary operations), which is essentially a "shortcut" way of performing a basic if. It has the following syntax
variable = condition ? <expression1 (if true)> : <expression2 (if false)>
The conditional operator will return one of two given values depending on whether the condition evaluates to true or false, for example:
var temp_x = x < (room_width / 2) ? 32: room_width - 32;
The above code will check the value of "x" against the value of half the room width and then if it is less it will set "temp_x" to 32 otherwise "temp_x" will be room_width - 32. Here are a few more examples of use:
draw_text(x, y, "The fee is " + (global.Member ? "$2.00" : "$10.00"));
path_start((global.level > 10 ? path_hard : path_easy;), 2, path_action_reverse, true);
--hp <= 0 ? instance_destroy() : score += 10;It is worth noting that you can nest conditional operations but that if you do then each operation will need to be enclosed in brackets, for example:
var c = a ? "foo" : (b ? "bar" : "wii"); // Correct
var c = a ? "foo" : b ? "bar" : "wii"; // Will cause an error
A repeat statement has the form
repeat (<expression>) <statement>
The statement is repeated the number of times indicated by the rounded value of the expression. For example, the following program creates five balls at random positions.
{
repeat (5) instance_create_layer(random(400), random(400), "Instances", obj_ball);
}This can be very useful to avoid typing out the same code multiple times, or for using arrays, or for counting through a number of operations etc... For example:
{
var i, total;
i = 0;
total = 0;
repeat (10)
{
total += array[i];
i += 1
}
draw_text(32, 32, total);
}
A while statement has the form
while (<expression>) <statement>
As long as the expression is true, the statement (which can also be a code block) is executed. Be careful with your while loops! You can easily make infinite loops, in which case your game will hang and not react to any user input anymore. Below you can find an example of a typical way to use "while":
{
while (!place_free(x, y))
{
x = random(room_width);
y = random(room_height);
}
}The above program tries to place the current object at a free position (this is about the same as the action to move an object to a random position).
A do is really the "do... until" statement as you cannot have one without the other. It has this form:
do <statement> until (<expression>)
The statement (which can also be a code block) is executed until the expression is found true, and the initial statement is always executed at least once. Be careful with your do loops, as you can easily make them loop forever, in which case your game will hang and not react to any user input anymore. Below you can find an example of a typical way to use "do... until":
{
do
{
x = random(room_width);
y = random(room_height);
}
until (place_free(x, y)); }The above program tries to place the current object at a free position (this is about the same as the action to move an object to a random position).
A for statement has this form:
for (<assigment1> ; <expression> ;<statement1>) <statement2>
This works as follows - First assigment1 is executed, then the expression is evaluated and, if it is true, statement2 is executed. Then statement1 is performed and then the expression is evaluated again. This loop will continue until the expression is found to be false.
Now, this may sound complicated when written like that, but you should interpret it as:
- The first statement initializes the for-loop.
- The expression tests whether the loop should be ended.
- Statement2 is the "step" statement that goes to the next loop evaluation.
This extremely useful for doing repetitive tasks that would involve multiple lines of code in any other way, and is commonly used as a counter for evaluating arrays, or drawing things. the following code example illustrates a typical use for this type of statement:{
for (var i = 0; i < 10; i += 1)
{
draw_text(32, 32 + (i * 32), string(i) + ". "+ string(scr[i]));
}
}The above code initialises a for loop, starting at 0 and counting up until 9, and then uses the loop value of i to draw the values stored in an array down the screen. Note how the for loop variable i is used to not only loop through the array, but to draw a number as well as tell GameMaker Studio 2 where to draw the values to in the room. This flexibility is one of the main reasons why for loops are so important in programming.
In a number of situations you want to let your instances complete an action depending on a particular value. You can do this using a number of consecutive if statements but when the possible choices gets above two or three it is usually easier to use the switch statement. A switch statement has the following form:
switch (<expression>)
{
case <expression1>: <statement1>; ... ; break;
case <expression2>: <statement2>; ... ; break;
...
default: <statement>;
}This works as follows:
- First the expression is executed.
- Next it is compared with the results of the different expressions after each of the case statements.
- The execution continues after the first case statement with the correct value, until a break statement is encountered.
- If no case statement has the right value, execution is continued after the default statement (it is not required to have a default statement, in which case no action will be taken).
Note that multiple case statements can be placed for the same statement. Also, the break is not required, and if there is no break statement the execution simply continues with the code for the next case statement. This means that you can create a hierarchy "switch" in which different sections of code are run depending on the input value. here is an example of a typical switch from a game:{
switch (keyboard_key)
{
case vk_left:
case ord("A"):
x -= 4;
break;
case vk_right:
case ord("D"):
x += 4;
break;
case vk_up:
case ord("W"):
y -= 4;
break;
case vk_down:
case ord("S"):
y += 4;
break;
}
}The above code uses switch to check for a keyboard event and then compares that to the cases listed. If it meets any of the required values then the corresponding code is executed. Note how in the code we have used the way that switch can check multiple cases and continue if no break is encountered to permit various keys to be used to get the same result. This is just one of the ways that you can permit multiple configurations for movement in your games.
The break" statement is used to end prematurely a for, repeat, while, do... until loop of some kind, or to tell a switch statement to end at that point, or to prematurely end a with call. Below you can see a few examples of how this can be used, and its syntax is simply:
break;
break in a for loop:
{
var i;
for (i = 0; i < 10; i += 1)
{
if array[i] = 234 break;
}
num = i;
}break in a repeat loop:
{
var i, temp;
i = 0;
temp = 0;
repeat (10)
{
temp += array[i];
if temp > max_total break else i += 1;
}
}break in a while loop:
{
var i;
i = 0;
while (!place_free(x, y))
{
x = random(room_width);
y = random(room_height);
if i > 50 break else i+=1;
}
}break when using with:
{
var count = 0;
with (obj_Enemy)
{
count++;
if count > 10 break;
hp = 100;
}
}
The continue statement has the form:
continue
If used inside of a statement that forms a loop (repeat, while, do... until or for), it will immediately jump back to the beginning of the loop as if the loop had run through and looped back. It will also do the same when using the with function, where it will cause the code to skip to the next instance and run again, but if used outside of context it will give an error.
Below is an example of its use in a for loop:
{
var i;
for (i = 0; i < 10; i += 1)
{
if array[i] = "" continue;
array[i] = "";
}
}The above code will skip back to the beginning of the loop if the array[i] value is already an empty string.
The exit statement has the form:
exit;
exit simply ends the execution of the current script or event. Note there is a slight difference in use here depending on the scope: if you use exit in a script is will simply exit the script and return to the code that called the script, however if you use this event in a code block from within an object, it will exit the entire event even if there are various separate code blocks after the function has been called. Typically it is used to avoid an instance running a specific block of code in, for example a collision event. The code below gives a simple example of this:
{
if !visible exit;
while (place_meeting(x, y))
{
x -= lengthdir_x(1, direction - 180);
y -= lengthdir_y(1, direction - 180);
}
}The above code checks a variable and if it resolves to true, then it exits the code block, otherwise it goes ahead and runs the rest of the code.
Note: It does not end the execution of the game. For that you need to use the function game_end.
As indicated in the section Addressing Variables in Other Instances, it is possible to read and change the value of variables in other instances. But in a number of cases you want to do a lot more than just change a single variable with those other instances. For example, imagine that you want to move all the ball objects in your game 8 pixels. You may think that this is achieved simply by the following piece of code:
obj_ball.y = obj_ball.y + 8;
But this is not correct, as the right side of the assignment gets the value of the y-coordinate of the first ball and adds 8 to it. Next this new value is set as y-coordinate of all balls, so the result is that all balls get the same y-coordinate, and even if you use the following:
obj_ball.y += 8;
it will have exactly the same effect because it is simply an abbreviation of the first statement. So how do we achieve this? For this purpose there exists the with statement in GML. Its global form is:
with (<expression>) <statement>
<expression> indicates one or more instances, and for this you can use an instance id, the name of an object (which indicates all instances of this object are to run the code block) or one of the special keywords (all, self, other). <statement> is now executed for each of the indicated instances, as if that instance is the current (self) instance. So, to move all instances of the ball object 8 pixels down, you can type:
with (obj_ball) y += 8;
If you want to execute multiple statements, put curly brackets around them, the same as you would around any other program. So for example, to move all balls to a random position, you can use:
with (obj_ball)
{
x = random(room_width);
y = random(room_height);
}Note that, within the statement(s), the indicated instance has become the target (self) instance that runs the code block, which means that the statements the original instance (that contains the with and the code block) has become the other instance. So for example, to move all balls to the position of the current instance, you can type this:
with (obj_ball)
{
x = other.x;
y = other.y;
}The with statement is an extremely powerful tool and is useful in many, many circumstances so it is important that you understand fully how it can be used. To help there are a few more examples of use below:
with (instance_create_layer(x, y, "Instances", obj_Ball))
{
speed = other.speed;
direction = other.direction;
}The above code will create an instance of obj_Ball and assign it the speed and direction of the instance that runs the whole code block.
with (instance_nearest(x, y, obj_Ball))
{
instance_destroy();
}The above code will destroy the instance of obj_Ball nearest to the instance running the code.
var inst;
inst = noone;
with (obj_ball)
{
if str > other.str inst = id;
}
if inst != noone target = inst;The above code is slightly more complex than previous ones due to it using a local variable. This variable is local to the script and not to the instance and so can be used and accessed by all instances that are referenced within the code block. So, in the code we have set it to the special keyword noone and then use the with construction to have every instance of obj_Ball check their str variable against that of the instance running the code block. If the value of the variable is larger, then they store their unique ID in the inst local variable, meaning that at the end of the code, only the instance with a value greater than the calling instance (or the keyword noone if none are larger) will be stored in the local variable inst. For more information on local variables see the section Variables And variable Scope.
The return statement has the form:
return (<expression>)
You only use the return statement in scripts, and it is used to return a value from the script to be used in further code or script calls. It should be noted that the execution of the script ends at the return statement, meaning that any code which comes after the return has been called will not be run. Here is a short example script called scr_sqr which calculates the square of whatever value is passed to it, and it includes error catching in case the argument that it is passed is not a real number:
{
if !is_real(argument0)
{
return 0;
}
else
{
return (argument0 * argument0);
}
}To call a script from within a piece of code, just act the same way as when calling functions - that is, write the script name with the argument values in parentheses. So, the above script would be called like this:
if keyboard_check_pressed(vk_enter)
{
val = scr_sqr(amount);
}
The GameMaker Language permits you to use the keywords begin and end instead of the more usual curly brackets {} when creating code blocks. The code example below shows how this works:
begin
if !visible exit;
while (place_meeting(x, y))
begin
x -= lengthdir_x(1, direction - 180);
y -= lengthdir_y(1, direction - 180);
end
end
Note that using these keywords is not typical and is provided as part of the language more for legacy suppport than for anything else.