When you first start writing GML, creating variables feels simple enough. You write something like health = 100;, use the value later, and everything seems fine.
Then your project becomes larger.
Suddenly, one enemy needs its own health, a temporary damage calculation should disappear after a function finishes, and your total score needs to be accessible from several different objects.
At that point, knowing how to create a variable is not enough-you also need to understand where that variable belongs.
That is the idea behind variable scope.
Learning Local, Instance, and Global Variables in GameMaker helps you decide how long information should exist and which parts of your game should be allowed to access it.
GameMaker also supports other scopes, including static variables and constants, but these three are the ones beginners encounter constantly.
Once the differences become clear, your GML code becomes easier to organize, debug, and expand.
1. What Does Variable Scope Mean in GameMaker?
A variable stores information, but its scope determines where that information can be accessed.
GameMaker explains that every variable belongs to a scope. The scope is largely determined by where the variable is first defined, and the currently executing code determines which variables are available.
Consider these three pieces of information:
player_health = 100;
global.score = 0;
var _damage = 15;
They may all contain numbers, but they serve very different purposes.
player_health might belong to one player instance. global.score can be accessed across the game. _damage may exist only temporarily while one event or function is running.
Choosing the correct scope prevents unrelated pieces of your game from interfering with each other.
A useful rule is simple: give a variable only as much scope as it actually needs.
2. What Are Local Variables in GML?
A local variable is temporary.
It exists only inside the event or function in which it is created and is discarded when that event or function finishes. GameMaker uses the var keyword to declare this type of variable.
For example:
var _damage = 20;
var _critical = false;
if (_critical)
{
_damage *= 2;
}
health -= _damage;
Here, _damage and _critical are only needed for this specific calculation.
There is no reason for the object to remember them forever.
Why Use the Underscore?
You will often see local variables written like this:
var _speed;
var _distance;
var _target;
The underscore is not required by GML. It is simply a common naming convention that makes temporary variables easier to recognize. GameMaker’s own documentation uses this style in many examples.
It becomes surprisingly helpful when reading longer functions.
You can immediately tell that _distance is local while something like move_speed may belong to the current instance.
When Local Variables Make Sense
Local variables are ideal for temporary calculations, loop counters, function results, intermediate coordinates, and values that should not survive after the current operation.
For example:
var _nearest_enemy = instance_nearest(x, y, obj_enemy);
if (_nearest_enemy != noone)
{
// Work with the enemy
}
Once this code finishes, there is no need to keep _nearest_enemy around unless another event needs it later.
Using local variables for short-lived data can also keep your code cleaner because you are not filling every instance with values that are rarely needed.
3. What Are Instance Variables?
Instance variables belong to individual object instances.
This is extremely important because a GameMaker room can contain many instances created from the same object.
Suppose you create obj_enemy and place five copies in a room. Each enemy could run this in its Create Event:
health = 100;
damage = 10;
move_speed = 2;
Although every enemy uses variables with the same names, those values belong to each individual instance. One enemy can have health = 40 while another still has health = 100.
That is exactly what you want.
If attacking one enemy changed the health of every enemy, your combat system would become rather interesting for all the wrong reasons.
4. When Should You Use Instance Variables?
Instance variables are best for information that describes the state or behaviour of one specific game object.
A player might have:
health = 100;
max_health = 100;
move_speed = 4;
can_jump = true;
An enemy could have:
health = 50;
attack_damage = 8;
alerted = false;
A treasure chest might contain:
opened = false;
gold_amount = 25;
These values need to survive between events.
For example, the player’s health may be created in the Create Event, reduced in a Collision Event, checked in the Step Event, and displayed in the Draw GUI Event.
That makes an instance variable much more appropriate than a local variable.
GameMaker also provides built-in instance variables such as x, y, speed, and sprite_index, so be careful when naming your own variables to avoid confusing them with existing built-in values.
5. What Are Global Variables in GameMaker?
Sometimes information does not belong to one particular object.
It belongs to the entire game.
That is where global variables become useful.
You create one using the global. prefix:
global.score = 0;
global.coins = 0;
global.current_level = 1;
Once declared, a global variable is accessible from different instances, structs, and functions and remains available until the game ends.
For example, an enemy could increase the player’s overall score when defeated:
global.score += 100;
A user-interface object could then display the same value:
draw_text(32, 32, "Score: " + string(global.score));
Both pieces of code are accessing the same shared information.
This makes global variables useful for genuinely game-wide systems.
6. Good Uses for Global Variables
Global variables work well for values that several unrelated systems genuinely need.
Examples might include:
global.score = 0;
global.music_volume = 1;
global.difficulty = 1;
global.current_stage = 0;
A settings menu, gameplay object, and audio controller may all need access to global.music_volume.
Similarly, several rooms may need to know the player’s overall score.
GameMaker’s documentation recommends keeping the declaration of global variables organized, such as initializing them together from a central object or function near the start of the game.
That makes them much easier to refrence later.
For example:
global.score = 0;
global.coins = 0;
global.music_volume = 0.8;
global.sound_volume = 1;
global.game_complete = false;
Now your shared settings are collected in one predictable place instead of being created randomly throughout the project.
7. Why Too Many Global Variables Can Become a Problem
Global variables are convenient, which is exactly why beginners can overuse them.
Imagine putting almost everything into global scope:
global.player_health = 100;
global.enemy_health = 50;
global.enemy_x = 300;
global.enemy_speed = 2;
global.door_open = false;
It might work in a tiny prototype.
But what happens when you have 30 enemies?
You would need seperate variables for each enemy, and multiple systems could modify them from anywhere in the project. Tracking down unexpected changes becomes increasingly difficult.
Instance variables solve that problem much more naturally because every enemy stores its own state.
Globals should therefore be reserved for information that truly needs to be shared across the whole game rather than used simply becuase they are easy to access.
It is also worth noting that the older globalvar declaration is deprecated. Modern GameMaker code should use the explicit global. prefix, which makes the scope much clearer when reading code.
8. Local vs. Instance vs. Global: A Practical Example
Imagine you are building an action RPG.
Your player has:
health = 100;
attack = 15;
These should probably be instance variables because they describe the player.
Your game also tracks:
global.total_gold = 0;
Gold may need to be accessed from shops, inventory menus, reward systems, save systems, and several different rooms, so global scope can make sense.
Now imagine calculating damage:
var _random_bonus = irandom_range(0, 5);
var _final_damage = attack + _random_bonus;
enemy.health -= _final_damage;
_random_bonus and _final_damage only matter during that calculation, so local variables are ideal.
The three scopes are working together rather than competing with one another.
That is how variables are usually used in real projects.
9. Accessing Variables From Other Instances
Sometimes one instance needs to change another instance’s data.
Suppose your player has found a particular enemy:
var _enemy = instance_nearest(x, y, obj_enemy);
You can then access a variable belonging to that instance using the dot operator:
_enemy.health -= 20;
GameMaker uses the dot operator to access a variable from another scope. The with statement can also temporarily execute code using another instance or struct as the current scope.
For example:
with (obj_enemy)
{
health -= 10;
}
That code affects the health variable of instances targeted by the with statement.
This is another reason understanding scope matters. Without it, code involving self, other, instance IDs, and with can become confusing very quickly.
10. Common Variable Scope Mistakes
One frequent mistake is using a local variable when the value needs to survive after an event finishes.
For example:
var _health = 100;
If this is created locally in the Create Event, you cannot simply expect _health to remain available later in the Step Event.
Another mistake is creating an instance variable for something that is only needed once.
If you calculate a temporary distance:
distance_to_enemy = point_distance(x, y, enemy.x, enemy.y);
but never need that value after the current function, a local variable may be cleaner.
Developers can also accidentally use the same names across scopes. Explicit prefixes such as global.score, the var keyword, and sensible local naming conventions help make your intentions obvious.
GameMaker additionally provides functions for checking, retrieving, and setting instance and global variables dynamically, although most beginner projects can rely on normal variable access initially.
11. A Simple Rule for Choosing Variable Scope
When you create a variable, ask one question:
Who needs this information, and for how long?
If only the current function or event needs it, use a local variable.
If one object instance needs to remember it between events, use an instance variable.
If genuinely unrelated systems across the game need the same shared value, consider a global variable.
This approach will not solve every advanced architecture decision, but it gives beginners a reliable starting point.
Remember that variables can store many different data types, including numbers, strings, Booleans, arrays, structs, methods, and resource references. Scope describes where a variable belongs, while its data type describes what kind of value it contains.
Keeping those two ideas seperate makes GML much easier to understand.
Understanding Local, Instance, and Global Variables in GameMaker is really about deciding who owns your game’s information. Local variables are perfect for temporary calculations inside an event or function.
Instance variables store persistent information for individual objects, such as health, speed, or current state. Global variables hold information that genuinely needs to be shared throughout the game.
The goal is not to choose one type and use it everywhere. Good GML code combines all three depending on the job. Try creating a small GameMaker project with a player, several enemies, and a score system.
Give each enemy its own health, calculate damage with local variables, and store the overall score globally. That simple experiment will make variable scope feel far more intuitive than memorizing definitions alone.
