Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more

YoYo Tech

Accessors For Data Structures and Arrays

Posted by Mark Alexander on 24 January 2014

In this article we're going to discuss some interesting extra functionality for data structures and arrays called Accessors. These accessors are simple logical expressions that permit you to add or change values within the structure, and they are written in a similar way as you would for working with arrays, only we use a special identifier symbol before the first argument to tell GameMaker Studio 2 that you are working on a (previously created) data structure or with directly with an underlying array.


Accessors

You can add, replace and get values and keys for the following data structure types using accessors:

Each one has been given its own symbol for accessing, changing or setting values, as shown below. For arrays, this functionality permits you to get direct access to a given array from a script, preventing the standard copy on write behaviour that you would normally expect (this is explained in more detail at the end of this article).

Also note that the symbols chosen to designate an accessor have been chosen specifically for their mnemonic nature (for example # is the DS grid identifier) which makes them easier to identify and remember.


ds_list [| ]

The accessor syntax for lists is:

list_id[| index]

So when you have used ds_list_create() to create your list, you would use the list ID (that you have stored in a variable) to reference it, with the "index" value being the position in the list to set or add. For example, the following code creates a list and then adds 10 entries, setting each entry to 0:

list = ds_list_create();
var _index = 0;
repeat(10)
   {
   list[| _index++] = irandom(9);
   }

Once you have created your list structure and filled it with data, to get values from the list you would have something like:

value = list[| 5];

The above will get the value from position 5 (the sixth index, since lists start at 0) and store it in a variable. Note that if you are using an expression to add a reference to an index that already has a value, then the previous value will be replaced rather than have a further index added to the list. To add further entries you would need to know the DS list size and add them to the end. It is also worth noting that you can set a list index that is greater than the size of the list being referenced, and this will set that value at the given index position, expanding the list at the same time, initialising all the positions in the list up to the given index as 0.


ds_map [? ]

The accessor syntax for maps is:

map_id[? key]

After creating your map with ds_map_create(), you would use the map ID that you have stored in a variable to reference it, with the "key" value being the map key to set or get. For example, the following code creates a map and then adds a few entries to it using this syntax:

map = ds_map_create();
map[? "Name"] = "Hamish";
map[? "Company"] = "MacSeweeny Games";
map[? "Game"] = "Catch The Haggis";

Once you have created your map structure and filled it with data, to get values from a specific map key you would have something like:

value = map[? "Name"];

The above will get the value from the key "Name" and store it in a variable. Note that if the map already contains the same key value as you are trying to add, it will not create a duplicate key with the new value, but rather the previous value will be replaced.


ds_grid [# ]

The accessor syntax for grids is:

grid_id[# xpos, ypos]

After creating your grid with the ds_grid_create() function, you would use the grid ID that you have stored in a variable to reference it, with the "xpos" and "ypos" being the position within the grid to get or set a value. For example, the following code creates a grid, clears it to 0, then and then adds a few entries to it:

grid = ds_grid_create();
ds_grid_clear(grid, 0);
var gw = ds_grid_width(grid) - 1;
var gh = ds_grid_height(grid) - 1;
repeat(10)
    {
   var xx = irandom(grid);
   var yy = irandom(grid);
   if grid[# xx, yy] == 0
        {
        grid[# xx, yy] = 1;
        }
    }

Once you have created your grid structure and filled it with data, to get values from a specific grid position you would have something like:

value = grid[# mouse_x div 16, mouse_y div 16];

The above will get the value from the given DS grid based on the mouse position (divided by the "cell" size in the room to get the correct location).


array[@ ]

The normal GameMaker Studio 2 way of working with arrays is copy on write, meaning that if you pass an array (for example) into a script, the original array is referenced until you change any of the array values, at which point it is copied. This means that to get the new values you have set, you must return the array from the script and re-assign it to the original array variable. For example:

//CREATE EVENT
a[9] = 0; //initialise a 10 value array 

//CALL A SCRIPT WITH THE ARRAY
a = scr_Set_Array(a);

//SCRIPT
var _a = argument0;
_a[3] = 500;
return _a;

However this can be limiting and is also slow performance-wise, especially when you have a very large array and it's being copied every time you run the script. However, there is an accessor for working with arrays too, with the syntax:

array[@ val];      //1D array
array[@ val, val]; //2D array

What this does is write directly to the underlying array, meaning that it is no longer copied into the script itself. Using the example code above as a reference, you would change it to this:

//CREATE EVENT 
a[9] = 0; //initialise an array to have 10 indices, each index assigned the value 0

//CALL A SCRIPT WITH THE ARRAY 
scr_Set_Array(a);

//SCRIPT 
var _a = argument0; 
_a[@ 3] = 500;

Notice that we now have no need to return the array as it hasn't been copied, but rather you have written the new value directly into the appropriate place in the base array.


Summary

That's about it for accessors! With the exception of arrays, using these will not speed up the performance of your code, as they call the same underlaying code as the functions they replace, however they do speed up your workflow as you have less to type, and are also easier to use within expressions. Another advantage they have over the functions, is that they lend themselves to making cleaner and more readable code, which is always a good thing!

Back to Top