• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Scripts

A

atxgamedesigner

Guest
Hello,

Previously I've done all of my scripting within the create and step events of my objects.
I've recently discovered using scripts, specifically with "state machines" and movement controls.

This seems to be quite a bit better way to program in GML.

I'd like to ask those more experience in scripts -

A) When do you use a script vs. scripting in a step event?
B) If you execute a script in a step event, is it executing once every step of the game?
C) If you can point me to some detailed documentation or tutorials on the subject, it would be very helpful!
 

YoSniper

Member
A) I usually write a script for one of two reasons:
1) I use the script to return a value, most often a sprite_index or some value associated with damage or scale. It becomes easier to modularize rather than burying it within the Step Event of one or more objects.
2) When I have a series of logic that pertains to the behavior of many similar objects.

B) Yes, the script will execute once for every time it is called within the Step Event, provided that "if" conditions and the like allow such.

C) I'll leave that to someone else who's more familiar with documentation.
 

TheouAegis

Member
Scripts help keep code organized by limiting duplicate code. You can use scripts to slightly speed up code by forcing it to break and moving on to the rest of the event (by returning out of the event).

In legacy versions of GM, since GM wasn't very user friendly with its search functionality, scripts were about the only way to code in legacy versions without pulling your hair out. There was also a lot more recursion allowed back then, too (which wasn't necessarily a good thing), so scripts could just keep calling themselves over and over until certain conditions were met (such as the program running out of memory). Studio forces you to be a bit little more cautious with recursive scripts nowadays.

Storing a set of values in arrays or data structures is a bit faster than using switch-return scripts, but you can use scripts as giant libraries/dictionaries of values to be returned indexed by whatever argument(s) you pass to the script. The data retrieval is slower, but takes up less memory.

Calling a script is minutely slower than just running the code itself, but the loss of speed is made up for by the ease of use and memory saved (for scripts called in multiple places).


Consider a code like:
image_xscale = sign(player.x-x | 1);
if sign(hspd) != image_xscale hspd *= -1;

You could put that in every enemy object, or put it in a script and just call the script from every enemy object. Instead of two lines copy-pasted, you have just 1 line copy-pasted.

Suppose you have 20 different types of enemies and each is initialized with its own values for certain variables. For example:
hp = 10;
atk = 1;
def = 1;
level = 1;
image_xscale = sign(player.x - x | 1);
spd = 1;
hspd = image_xscale * spd;
vspd = 0;
alarm[0] = 64;

hp = 22;
atk = 3;
def = 5;
level = 4;
image_xscale = sign(player.x - x | 1);
spd = 2.5;
hspd = -image_xscale * spd;
vspd = 1;
alarm[0] = 1;

And so on. You could copy-paste-edit or type all that out for all enemies, or you could make a script that looks up the object_index of the enemy and assigns the values automatically itself.


Scripts are also indexed like any other resource, so you can call them indirectly rather than looking them up for direct calls. I haven't tested, but I'm pretty sure child scripts (script tabs) are immediately indexed from the parent script, so they should all be indexed in immediate successive order. So if you had a state machine in place with each child script holding the code for a particular state, then you could just do:
script_execute(myStates+state);

...where myStates is the ID of the parent script and state is the numerical reference (from 0) of the current state.


In most cases you don't have to use scripts and they are usually unnecessary, but once in a while it will just make sense to use a script or scripts instead of typing out longer codes.
 
A) When do you use a script vs. scripting in a step event?
If I am writing large portions of code in any object events, I will always write them in multiple scripts instead. It makes it easier to debug and easier to organize.

B) If you execute a script in a step event, is it executing once every step of the game?
Whatever your room_speed is set at, it will execute the step event of an object that many times per second. So if you have an object, with a step event, and the room speed is at 30, it will execute the object's step event 30 times per second.

C) If you can point me to some detailed documentation or tutorials on the subject, it would be very helpful!
Heartbeast does a wonderful series on making a jrpg styled game from scratch. The videos are very informative and incredibly user-friendly. I would highly suggest them:
 

TheouAegis

Member
B) If you execute ANYTHING in the Step Event, it will be executed every step of the game. The only time any code (including scripts) will be executed just once is Create Event, Destroy Event, User Event (unless you call the user events from a step event), Creation Code, Game Start, and Game End. If you have an instance calling a script 4 times in a step event, then that script will run 4 times per step; if the room speed is 60, the script will run 240 times per second. If you have one object calling a script once in a step event and you have 4 instances of that object active in the room, then the script will run 240 times at 60fps. If you have four objects with one instance each in the room and each object calls that script one time in a step event, then the script will run 240 times per second at 60fps.

I'll rephrase what I said earlier: Code in a Step event is "stray code"; it is not an indexed resource and is only available to the program when an instance with that code is active in the room. Scripts are indexed code resources and are always available to the program. Do you want to easily reference code? If yes, then put your code in scripts, otherwise just use the code block in the step event.
 
I write all my code in scripts. A) Mostly because I hate digging through the object interface to get to the code I need, B) because I personally feel like having my code organized in folders in the resource menu to be much simpler to keep organized, and C) due to the modular structure of my code, I can quickly slap together many similar, but functionally different, object types with a few lines of code. And of course, D) reusable code gets turned into functions!
 

NightFrost

Member
I put almost everything in scripts. It greatly helps organizing chunks of code, lets me easily reuse them, simplifies debugging and makes them more portable to other projects. The downside is a large amount of separate scripts. To combat that I group together scripts that serve the same purpose and invoke them with a variable that states which one is required. For example, a procgen script of mine is called scr_ScriptName("init"), scr_ScriptName("generate"), scr_ScriptName("cleanup") and scr_ScriptName("reset") depending what needs to be done. I've been wanting to figure out a simple way to pass varying amount of variables to scripts without having to resort to arrays (because they're so clumsy in GML) but I haven't had the time for that.
 
I've been wanting to figure out a simple way to pass varying amount of variables to scripts without having to resort to arrays
A recentish update removed the 16 argument limit to passing data to functions and scripts. Not sure if it has been passed to the stable release or not, but it's at least in the beta release.
 

NightFrost

Member
A recentish update removed the 16 argument limit to passing data to functions and scripts. Not sure if it has been passed to the stable release or not, but it's at least in the beta release.
Ah right, I read about that but forgot at some point... However, doesn't GM give an error if a script is called with too many or few parameters (mismatch between incoming parameters and argumentX declarations), so I'd need to "pad up" a call when I need to hand over less? You can't declare a function in GML so you can't give its parameters default values.

EDIT - I mean I cannot say:
Code:
function DoSomething(Param1, Param2 = false, Param3 = 0){
    ...
}
and then just
Code:
DoSomething("foo");
 

ZeDuval

Member
You need to
1.) use the argument-array instead of the argument-vars =>
Code:
argument[0], argument[1], argument[3]
instead of
Code:
argument0, argument1, argument2
and 2.) utilize the variable argument_count, in combination with a loop, if-clauses or a switch/case.
To have something like default values, you'd need to set them up inside the script rather than in the script-call.
Code:
var a=argument[0], b=argument[1], c=100; // default
if argument_count>2{
c=argument[2]; // override
}
 

NightFrost

Member
Interesting ideas, I'll have to play around with those some time. Of course, it would be even better if GML supported functions in a standard way. One of the reasons why I'm very interested in seeing what GM2 will bring...
 
Top