It's been 5 years since my "variable references in GameMaker" post and people are still interested in passing variables by reference, so this I'm giving the idea a little refresh with new tools that are now available.
The idea
The concepts didn't change from the last time, but GameMaker did - you can read more about this in another post of mine, but what matters for this is that we have structs and constructors now.
Getting it done
So we can make a little constructor with get
/set
functions that will call reflection functions
to get/set the variable.
function VarRef(_inst, _varname) constructor { inst = _inst; varname = _varname; static get = function() { return variable_instance_get(inst, varname); } static set = function(_value) { variable_instance_set(inst, varname, _value); } }
This will also work for structs
(variable_instance_get
and variable_struct_get
are synonyms for the same function),
and we'll be able to do
var my_x = new VarRef(self, "x"); x = 100; show_debug_message(my_x.get()); my_x.set(200); show_debug_message(x);
Other wrappers can be similarly accomplished:
function ArrayItemRef(_arr, _index) constructor { array = _arr; index = _index; static get = function() { return array[index]; } static set = function(_value) { array[@ index] = _value; } }
and used:
var arr = [1, 2, 3]; var item = new ArrayItemRef(arr, 1); show_debug_message(item.get()); item.set(4); show_debug_message(arr[1]);
Making it shorter
val = ref.get()
and ref.set(val)
are good, but what if you wanted to make this shorter?
Obviously you can't have val = ref
and ref = val
because that's not supported,
but how about val = ref()
and ref(val)
?
Let's have a look at the code:
function variable_ref_create(_inst, _varname) { with ({ __inst: _inst, __varname: _varname, }) return function() { if (argument_count > 0) { variable_instance_set(__inst, __varname, argument[0]); } else return variable_instance_get(__inst, __varname); } }
When you create a function "value" in GameMaker using function(){}
,
it automatically binds to the current self
, and code inside
the function will execute in context of that instance/struct.
By doing with (struct) return function(){}
, we can create a little struct
(to hold information about what variable of which instance we need)
and bind a function to it.
Calling this bound function with no arguments will then return the current value of the variable and calling it with one argument will change its value to a new one.
This can subsequently be used like so:
var my_x = variable_ref_create(self, "x"); x = 100; show_debug_message(my_x()); my_x(200); show_debug_message(x);
Similarly, this can be applied to other types of references:
function array_ref_create(_array, _index) { with ({ __array: _array, __index: _index, }) return function() { if (argument_count > 0) { __array[@ __index] = argument0; } else return __array[__index]; } }
and used:
var arr = [1, 2, 3]; var item = array_ref_create(arr, 1); show_debug_message(item()); item(4); show_debug_message(arr[1]);
Pretty neat and a little cursed, isn't it?
very cool will use
Something I also like to add to the mix, is that variables can now be hashed from either structs or instances. Which does matter if you’re looking up the same variable multiple of times. (This applies to 2023.4+)