LearnGML

Data Structures

We should now be familiar with basic variables, operators and program control, however these tools alone aren’t enough to write increasingly complex code. In particular, receiving, understanding, manipulating and saving complex data is difficult without additional tools. This is where Data Structures come into play. These variable formats allow large amounts of data to be efficiently and effectively manipulated in simple and complicated manners alike. We shall cover the most commonly used Data Structures in GML, as well as legacy options that may still be encountered but should generally be avoided.

Arrays

Arrays are essentially a collection of values that are bundled together. These values can be any combination of numbers, strings, variables, assets and so on. An array can be any shape and size, and each entry only takes up one spot in the array. Lets look at some examples:


// Arrays can be defined like this...
my_array = [10, 20, 30, 40, 50]

// ... or like this (note arrays are 0 indexed)
my_array = [];
my_array[0] = 10;
my_array[1] = 20;
my_array[2] = 30;
my_array[3] = 40;
my_array[4] = 50;

// You can edit an array entry like this as well
my_array[0] = 5;

// And you can retrieve an entry from an array as well
answer = my_array[2]; // answer is equal to 30

// You can delete an entry from an array and insert a new entry at a position
array_delete(my_array, 0, 1);
array_insert(my_array, 0, "hello");

As you can see, each entry in an array can be accessed using its index. You can think of an array like a street, and each entry is like a house on the street with its own street number, or index. Arrays will resize themselves to fit their contents, so if you delete an entry in an array it will shrink by one spot and every entry after the deleted entry will be pulled backwards one spot. Similarly, if you insert a new entry in the middle of an array, every entry afterwards will be pushed forward one spot. The two array functions at the end of the code above are some of the built in array functions in Gamemaker, you will use a variety of these in your gamemaking journey.

Arrays don’t just have to be one dimensional, in fact they can have as many dimensions as you’d like. Two dimensional arrays in particular are quite frequently used, especially as a representation of a grid. You can think of these as a city block, where the first index is the street and the second index is the street number.


// 2D arrays can be defined like this...
my_array = [[10, 20, 30], [40, 50, 60]];

// ... or like this
my_array = [];
my_array[0][0] = 10;
my_array[0][1] = 20;
my_array[0][2] = 30;
my_array[1][0] = 40;
my_array[1][1] = 50;
my_array[1][2] = 60;

So, when should you use arrays? Whenever you need to store multiple bits of data together in a bundle, and the order/position of each bit of data is important. One common example is to use a two dimensional array to represent a grid pattern, with the two dimensions representing the x and y positions. If you were to make a card game, arrays are perfect for storing the player’s deck and hand.

Structs

The other main data structure that you will use is a struct . A struct can be thought of as a box that contains other variables. Unlike an array, the position or index of these variables is irrelevant, instead each entry in a struct is accessed by using its name, as if each item in a box had a name tag attached that you used to decide what item to pull out.


// Structs can be defined literally...
my_struct = {name : "sword of doom", damage : 15, range : 3};

// ...or added to in three different ways
my_struct = {};
my_struct[$ "name"] = "sword of doom";
my_struct.damage = 15;
variable_struct_set(my_struct, "range", 3); // This method isn't really recommended

// And you can retrieve the struct's contents in the same ways
name = my_struct[$ "name"];
damage = my_struct.damage;
range = variable_struct_get(my_struct, "range");

So when should we use structs? Whenever we need to bundle data together and the order does not matter. Often times, an array could be used for the same job as a struct, however accessing the contents of a struct can be a lot more convenient than from an array, for example grabbing my_struct.damage is a lot more sensible than my_array[0].

Constructors

I don’t think I can explain constructors better than the manual, so please read the section on constructors . Constructors are incredibly useful for creating templates, or even “classes” similar to other programming languages. The real power of constructors is that you can add your own methods, essentially functions (we will cover these next), that let you execute little snippets of code within the struct, such as this:


// Enemy Constructor
enemy = function(_name, _hp, _damage) constructor {
    name = _name;
    hp = _hp;
    damage = _damage;

    take_damage = function(_damage) {
        hp = max(0, hp - _damage);
    }
};

// Create a new enemy and reduce its hp by 5
my_enemy = new enemy("slime", 15, 4);
my_enemy.take_damage(5);

Other Data Structures

Gamemaker also contains a number of additional data structures which contain a ds_ prefix:

Data Structure Definition
ds_list Lists function similarly to arrays in that data is stored sequentially, and there are many functions to insert, extract and manipulate the sequence of data in the list. largely deprecated by arrays.
ds_map Maps function similarly to structs in that each data point has a key and a value, or you could think about it as a label and a definition. Entries in maps are not sequential or sorted. Largely deprecated by structs.
ds_grid Grids function similarly to 2 dimensional arrays, as they contain a grid of values identified by their x and y positions within the grid.
ds_stack Stacks are a Last In First Out (LIFO) structure, where new entries are addedon top of the stack and entries are also removed or accessed from the top.
ds_queue Queues are a First In First Out (FIFO) structure, where new entries are added on bottom of the queue and entries are removed or accesed from the top.
ds_priority Prirority queues are similasr to queues however the order in which entries are stores isn't determined by when they were added to the queue, but rather based on a prirotiy value assigned to each entry.
Additional Resources
Method Variables GML Data Structures