Jump to content


Photo
- - - - -

Scripting Tutorial


  • Please log in to reply
16 replies to this topic

#1 ramses12

ramses12

    6

  • GMC Member
  • 5769 posts
  • Version:GM8.1

Posted 12 December 2009 - 06:26 PM

Additional Info
  • 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);
    			 };
The repeat statement repeats the code inside it n times, n being the given expression. Of course an expresion can be a number or a variable:
r=50;
			   repeat(r){
			   instance_create(random(room_width),random(room_height),obj_ball);
			   };
is the same as
repeat(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));
This is a script that returns a number, in this case the sum of its arguments. Of course a script can return a string as well. When you test the game, if everything is done correct, a text will show up with the string of 15. Note that any code you write after the return keyword is called won't be executed, for the script automatically terminates its process when it returns a value. However there would be no problem in using something like:
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();
This will continuously ask the player until he presses the correct answer. Of course in order to make the conversation a bit more realistic you can pass an argument, developing the script so it shows different messages.
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.

  • 1

#2 KC LC

KC LC

    Ex-Administrator

  • GMC Elder
  • 5309 posts

Posted 14 December 2009 - 12:50 PM

This tutorial was overlooked for approval, and fell near the bottom of the page. So I'm bumping it back to the top.
  • 0

#3 weckar

weckar

    Helping Hand

  • GMC Member
  • 2616 posts
  • Version:Unknown

Posted 14 December 2009 - 12:56 PM

Much of the explanation of naming arguments has fallen into the code block, might want to clean that up.

Great guide though.
  • 0

#4 ramses12

ramses12

    6

  • GMC Member
  • 5769 posts
  • Version:GM8.1

Posted 14 December 2009 - 01:04 PM

Fixed. Thanks! And Thanks KC!
  • 0

#5 Yambam

Yambam

    GMC Member

  • GMC Member
  • 636 posts
  • Version:GM8

Posted 14 December 2009 - 06:06 PM

thanks for helping out the argument[0-100000] (or something)
i learned something new ^_^
  • 0

#6 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 22599 posts
  • Version:GM:Studio

Posted 14 December 2009 - 06:24 PM

This is a nice explanation of scripts for those that want to advance in GML and do bigger and better things... My only complaint is that maybe you should add a comment at the end warning not to rely on scripts too much as there is an associated CPU overhead... Running code direct in the object is actually quite a bit quicker... I find myself using a script to test my coding and then when Im happy with the code I place it in the object...
  • 0

#7 ramses12

ramses12

    6

  • GMC Member
  • 5769 posts
  • Version:GM8.1

Posted 14 December 2009 - 06:33 PM

I'll add that. It's important to gather as many informations and questions as possible in order to provide a tutorial as wide as possible.

@Yabam: I'm glad you've learnt something.

Edit: Added the mention.

Edited by ramses12, 14 December 2009 - 06:47 PM.

  • 0

#8 Desert Dog

Desert Dog

    GMC Member

  • GMC Elder
  • 6409 posts
  • Version:Unknown

Posted 14 December 2009 - 07:49 PM

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.

You should try to explain WHY it's more cpu intensive than normal code... which, I'll quote Flexaplex on:

Something else to be aware of is that you can only give a script a maximum of 16 arguments. Also Game Maker will automatically assign all 16 arguments a value even if you don't put one in yourself, a value of 0 is given to all arguments that you don't assign at the end of calling a script. This is why (and you should take note of this) that calling a script is actually quite slow in comparison to executing code inside an object normally, it is therefore not advised to use scripts for very simple things.


Also,

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.

Well, GML scripts can return either real values, or sting values. It's a minor point however, because since they are only those two 'types' even a beginner shouldn't be confused by it. However, as an example, I'll write a super quick script, which takes a real argument, and returns a string.
var ii, answer;
ii=show_message_ext("What do you want to say?","Hi","Bye","Your ugly");
answer=get_answer(ii);
show_message(answer);

get_answer()
var choice;
choice=argument0;
switch(choice)
{
	 case 0:
	 return "Say something!";
	 break;
	 case 1:
	 return "Hi";
	 break;
	 case 2:
	 return "K, bye";
	 case 3:
	 return "*He punches you*";
	 break;
}

From what I've read of your tutorial (I admit, I skimmed over it), you actually haven't mentioned that scripts can return strings.

Anyway, it seems a pretty nice example, showing lots of examples in the explanations, which is good. ^_^
  • 0

#9 ramses12

ramses12

    6

  • GMC Member
  • 5769 posts
  • Version:GM8.1

Posted 15 December 2009 - 11:51 AM

Well, GML scripts can return either real values, or sting values. It's a minor point however, because since they are only those two 'types' even a beginner shouldn't be confused by it. However, as an example, I'll write a super quick script, which takes a real argument, and returns a string.

Technically you've said yourself that there are three types. Anyway strings are arrays of binary characters too.

From what I've read of your tutorial, you actually haven't mentioned that scripts can return strings.

Well it was clearly that a variable can be a string too, but anyway I've mentioned that more specific now.

Update: added a contents table and 3 more chapters.
  • 0

#10 PlasticineGuy

PlasticineGuy

    GMC Member

  • New Member
  • 2384 posts

Posted 15 December 2009 - 12:21 PM

GM does have a void return value. Make an empty game and a script called void. Leave the script blank. In room creation code put:
var n;
n = void();
if(is_real(n) || is_string(n)) {
	show_message("Is a real or string!");
}
else {
	show_message("WTF? Void?");
}
show_message(string(n));
game_end();
You will get the message "WTF? Void?". The value is 0.00.
  • 0

#11 ramses12

ramses12

    6

  • GMC Member
  • 5769 posts
  • Version:GM8.1

Posted 15 December 2009 - 12:43 PM

And if you draw string(n), the game will eventually freeze. Probably GM bug.
  • 0

#12 ramses12

ramses12

    6

  • GMC Member
  • 5769 posts
  • Version:GM8.1

Posted 04 February 2010 - 06:28 PM

Ummm I have mentioned that:

However you can return a data structure, which is severally used and also recommended (pro only)

ds_list_add() refers to a data structure.
  • 0

#13 robcortez1787

robcortez1787

    GMC Member

  • New Member
  • 3 posts

Posted 04 February 2010 - 09:37 PM

Now this is helpful. Thanks guys.

do you have idea how to make a flash games? just a simple one will do. Like car racing?
I'm practicing on developing some games. I'm enjoying it.
  • 0

#14 PlasticineGuy

PlasticineGuy

    GMC Member

  • New Member
  • 2384 posts

Posted 05 February 2010 - 08:13 AM

And Flash games have to do with Game Maker... what?
  • 0

#15 ramses12

ramses12

    6

  • GMC Member
  • 5769 posts
  • Version:GM8.1

Posted 05 February 2010 - 12:16 PM

do you have idea how to make a flash games? just a simple one will do. Like car racing?

Game Maker is not related at all to Adobe Flash. It is a totally different programming languace (the Game Maker languace is called GML and Flash's languace is called ActionScript). If you want to make a small car racing game in Game Maker, first try the top-down street racing example inlcuded in GM.
  • 0

#16 peter john

peter john

    GMC Member

  • New Member
  • 18 posts

Posted 05 February 2010 - 05:53 PM

this is really a interesting one!!....gud wrk
  • 0

#17 sonicjms

sonicjms

    GMC Member

  • New Member
  • 1 posts

Posted 10 February 2011 - 05:14 PM

scr_create_random(10); doesn't seem to work is this because im using GM8 or something else?
  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users