- Title: Scripting tutorial
- Description: A guide for those who want to learn GML scripts
- GM Version: GM 7
- Registered: No
- File Type: gmk
- File Size: approx. 25 kB each
- File Link: http://solidfiles.com/d/YV1F/get - Tutorial 1
http://solidfiles.com/d/3Y6P/get - Tutorial 2
http://solidfiles.com/d/NqZi/get - Tutorial 3
- Skill Level: Novice to intermediate
Scripts are probably the first step to an organised program, and an opened window to the advanced GML and programming in general.
Contents
Read this contents to see if you are interested in any of the subjects covered in this tutorial.
- About scripts
- Tutorial 1: Creating some instances within a script
- Tutorial 2: Using the keyword 'return'
- Tutorial 3: Using recursive scripts to create a basic quiz
- Scripts used to extend the GML
- Naming arguments
- Scripts returning two or more values and scripts accepting more than 16 arguments
- Variable argument scripts
- Script design and optimisation
- About argument_relative
- Executing scripts by name
About scripts
What is a script? A script is a function made by the GM user himself. Thus you can define your own functions to use when needed. The advantages are several; think about writing a long code with some parts which are always the same. It's much better to create a script and use it every time you need to write that code part. Another important aspect is that a script can use arguments, as a function does. As an example, random(x) is a function that returns a random value between 0 and x, x being the argument. place_free(x,y) is a function with 2 arguments, x and y. In a custom script, you can retrieve the value of these arguments by using the argument0, argument1, argument2, ..., argument16 variables or the argument[] array. There is actually no difference between the first variant and the second one, except for programming techniques that requre an automatic calculation of arguments.
Let's take an example:
Tutorial 1: Creating some instances within a script
- Make a new game
- Create an object called obj_ball with a ball sprite, and object called controller (without any sprite).
- Create a room.
- Place an instance of controller in the room.
- Create a new script and call it scr_create_random. In it write the next code:
repeat(argument0){ instance_create(random(room_width),random(room_height),obj_ball); };
r=50;
repeat(r){
instance_create(random(room_width),random(room_height),obj_ball);
};is the same asrepeat(50){
instance_create(random(room_width),random(room_height),obj_ball);
}; As has already been told, argument0 is the script variable which stores the first argument. Of course, these variables cannot be used outside a script, term to apply to argument[] array and argument_relative variable too. After finishing with the script, write the next code in the create event of object controller:
scr_create_random(10);After this run the game. If you haven't done anything wrong, 10 instances of obj_ball will show up on the screen. After this, change the scr_create_random(10); code to:
scr_create_random(get_integer("Insert a number",0));Now, the player will be able to insert a number and your script will create that number of instances. Now, you should be familiar with the basic of scripts. The next oportunity of scripts is that they can actually return a value. By returning a value, a script can be used as an expression (or a value). In GM every function returns a value, in order to avoid any kind of errors and to allow functions act like variables in mathemathical assignements etc.
It is a known fact that in C++ functions returning no values are called void functions and functions returning a value are called int functions (not mentioning other more advanced facts). In GM, there's no such difference and there can be scripts which don't return a value in some cases and do in others. My personal advice is to return a value in any script.
Back to functions and scripts, the only way to return a value is using the keyword return. Let's see how this works:
Tutorial 2: Using the keyword 'return'
- Create a new game
- Make a controller object and place it in a room
- Create a script and call it scr_sum. Inside it, write:
return argument0+argument1;
- In the draw event of the controller, write: draw_text(20,20,string(scr_sum(8,7));
if(argument0<=0)return 0; else return sqrt(argument0);(this would be a safe square root script).
When you understand how the scripting mechanism works, a next step would be calling a script inside a script.
When you call a script inside a script, you have to remember that using the calling script's arguments as arguments for it might help in some situations:
//script named scr_sum return argument0+argument1;
//script named scr_decrease return argument0-argument1;Main script:
return scr_sum(argument0,argument1)*scr_decrease(argument0,argument1);This script returns the value of ( a+b )( a-b ) using two other scripts. Of course it's just easier to write return (argument0+argument1)*(argument0-argument1) but in a larger program, when you need to structure the instance actions and coordinate then properly, it's useful to make a structure of scripts and subscripts.
When you call the same script as the one you're in, this is called recursion. But in the case you want to make a recursion you have to be careful to stop it from looping forever.
Tutorial 3: Using recursive scripts to create a basic quiz
- Open the previously created game, and make a new script called scr_quiz, with the next code:
if(show_message_ext("What is the approx. value of pi?","3.41","3.14","3.2")!=2)scr_quiz(); - In the create event of the controller, write scr_quiz();
Recursivity can be used in several situations; searching algorythms, repeated user imput and yet other things. Think about drawing a fractal or creating chain reactions.
Scripts used to extend the GML
GML is an extensible languace, and one way to extend it is using scripts. When scripting for other users, or even for yourself, you have to consider making the script as flexible as possible, in order not to cause all sorts of errors. The script should be able to work even in unexpected situations. Always remember to make your scripts secure! As an example, never forget to delete a system created in a script before returning. As a note, as Mark13673 well mentioned, scripts slow a bit the process of the game, using additional CPU. However when the script stops its execution, the speed is restored.
Naming arguments
Naming arguments only means creating vari type variables equal to arguments, like in the next code:
var xx,yy,dir,spd,time; xx=argument0; yy=argument1; dir=argument2; spd=argument3; time=argument4;Naming the arguments in a script is always important for several reasons: First of all, it makes much easier the reading of code. Secondly, it requires much less effort when writing the script itself; you don't have to remember what each argument exactely does. Eventually, the code would be much easier to check for eventual errors.
But you have to remember that those are only variables and not arguments themselves. Thus changing a variable doesn't change the argument. And also remember that these variables are freed at the end of the script.
Scripts returning two or more values and scripts accepting more than 16 arguments
Normally this can't be done. However you can return a data structure, which is severally used and also recommended (pro only) or an array. This is a script returning a data structure index:
var ds; ds=ds_list_create(); ds_list_add(ds,argument0); ds_list_add(ds,argument1); return ds;You can now use the id of this data structure in other related scripts too. Scripts setting values to an array are a bit harder to do, because you can't return an array itself. You need to pass the array name as a string and use the variable_local_array_get() and variable local_array_set() functions. Here is an example:
var array; array=argument0; variable_local_array_set(array,0,"value0"); variable_local_array_set(array,1,"value1"); variable_local_array_set(array,2,"value2"); variable_local_array_set(array,3,"value3");remember that in this case the array argument has to be passed as a string in order to be compatible with the variable_local_array_set() function. Same things apply to 17+ arguments scripts.
Variable argument scripts
As you know, there are some GM functions like min(), max(), choose() and others, which are able to use a variable number of arguments. Even this seams to be easy, there is no such thing as "number_of_given_arguments" , so you have to define it yourself. Generally, a variable argument script would want to loop through the whole argument list and pick one of the values. But how can the script know how long is this argument list? This can be achieved in two ways: sacrificing an argument which stores the number of arguments (safer) and using a code like
if(string(argument[n])=="0")break;. Used in a for loop this stops the process when 0 is met (an empty argument has the value of 0). Thus the funtion min() can be coded as:
var r;
r=argument0;
for(i=0;i<=16;i+=1){
if(string(argument[i])=="0")break;
//note that here the argument array must be used instead of variables.
if(r>argument[i])r=argument[i];
};
return r;Unfortunately the script will stop when it meets a 0, but there can be done better codes which for example check if all the next arguments have the value of 0. If you wonder why I used string(argument[i]), it's because some variable argument script might work with strings, so a normal if(argument[i]==0) would cause a "cannot compare arguments" error. Here is a code I designed for a secure number of values checking:
var i,argnumb;
i=0;
argnumb=0;
while(i<=15){
if(string(argument[i])!="0")argumnb+=1;
else argnumb=0;
i+=1;
};
return 15-argumb;Script design and optimisation
A basic advantage of using scripts is that you can avoid writing a code twice, making a script for that and using arguments for small differences. But sometimes there comes the circumstance of making two scripts that have almost the same code but are supposed to return different values. For example, let's say you create a script which returns how many instances of type object are colliding with a given polygon and you create another script which returns the id of the first instance which collides with the given poly, and another script which returns a ds_list containing all instances which collide with the poly. Or, as another example you create a script which returns the smallest value of a a given array and another script which returns the largest value of a given array. Now, why use 2 or 3 scripts with almost the same code instead of using one single script returning one of those values depending on an extra argument? Thus you can execute the script like this:
array_find("my_array",8,"min");About argument_relative
Game Maker uses two user interaction systems: GML and D&D. D&D actions are nothing else than GML functions, used under a graphical interface. Thus when creating a D&D action library with ExtensionMaker (Link), you have to write the source code of a script which is called by GM when it executes a given action. A D&D action has maximum 5 arguments and a "relative" checkbox. argument_relative is 1 if the "relative" checkbox is checked and 0 otherwise.
Executing scripts by name
Executing scripts by name can be done with the function called execute_string(); Unfortunately this slow. Here is a script that executes a script by its name given as string:
var str,i;
str=argument0;
i=0;
while(script_exists(i)){
if(script_get_name(i)==str)execute_script(i,argument1);
};Note that this should be a variable argument script.Thanks for reading this tutorial! Please post any questions or comments.
~Ramses12
Edited by ramses12, 02 January 2010 - 09:30 AM.











