E
ECEngineering
Guest
GM Version: GM:S 1.4, but should work on any version if readjusted.
Target Platform: Windows / All
Download: here
Built-in data structures are still more efficient than this method. It's purpose is to let you create your own custom data structures that do not exist in GameMaker.
This tutorial should help you create your own data structures with ease. As an example, I will be creating my own custom list. If you are not familiar with the term, OOP stands for Object Oriented Programming.
First thing you will have to do is create two scripts. One will create an instance of a "class", and the other one will delete it.
Setting everything up
First, let's create a "new" script that will create an instance of our class/object:
Script: new
What this will do is create and instance of the object sent as the argument, then it will deactivate it to not waste our processing power and finally, return the reference to it.
This way of creating objects is incredibly optimized as it only takes up memory. I've tested it by creating 100000 objects this way and it didn't affect performance at all.
Now, let's write the "delete" script that will free our instance from the memory once we don't need it anymore.
Script: delete
Before we can use "instance_destroy" function to delete the instance, we must first activate it because you can't access deactivated instances by using "with".
Now, we have everything that we need to work with OOP, so we can begin creating our own data structures!
Creating data structures
Before we start creating our own data structures, I want to address a few things. It is possible to have something similar to class-functions, but in order to do that, you would have to activate the instance, call all the functions that you want to call, and then deactivate it again. As this usually looks very "ugly", I will be doing it the same way YoYoGames did it. We will create scripts that will take the reference of the instance as an argument in the similar manner as the built-in GM:S data structure functions do (ds_list_size(id)).
First thing we'll have to do is create two objects. We'll call them "cls_node" and "cls_list". The image below ilustrates the concept of lists.
The list consists of a chain of nodes that have two fields. One field holds their value, while the other one is holding the reference to the next node in the chain.
We can now write this code in the create event of the "cls_node":
cls_node Create Event:
The "data" variable will hold data, while the "next" variable will hold the reference to the next node in the chain.
That's it for the "cls_node" object. Now, we will be working on our "cls_list" object. If you take a look at the image above again, you will notice that there is something called "head" pointing to the first node in the list. That "head" is the list (well, at least the minimum you need in order to create it). In order to optimize our list, beside this "head" field in the list, we will add two more fields. First one will be "tail" which will always point on the last element so we don't have to iterate through the whole list when adding new values to it's top, and the second one will be "length" which will hold the length of the list so we don't have to iterate and count each time the request for it's size has been sent. We will put this in "cls_list" create event:
cls_list Create Event:
As I already said earlier, the "head" variable will hold the reference of the first node in the list, the "tail" variable will hold the reference of the last node in the list and the "length" variable will hold the current list size.
The last thing we'll have to do is create some functions for our list. As I already said, you can create in-class functions and call them directly from the object by activating it and using "with" to call the function, but we will not be doing it because it is not convenient.
I will give you examples on some functions but not all of them as this is not the tutorial on lists in particular, but on creating your own data structures in general.
Script: list_size
This function will simply return the size of the list by reading the variable
Script: list_add
This function will add values to the end of the list by creating a new node, setting our old tail's next value to be this node, and nominating it as the new tail.
Script: list_find_value
This function will iterate through nodes until it reaches the requested one. After that, it returns it's data.
Script: list_insert
This function will iterate until reaching the node with the "position-1" index, then create a new node, set it's next value to the node currently occupying it's index and set the next value of the previous node to this new one.
Script: list_free
This function will iterate through all nodes, deleting each one of them. In the end it deletes the list itself.
Using our Data Structures in game
We can now use these data structures from anywhere in the code. Here is the example of how you may use this in your game:
Making our Data Structures persistent:
You may notice that ticking the "persistent" box in the object editor isn't enough to make our structures persistent. GameMaker:Studio does not allow deactivated instances to move through rooms even though they are persistent. To solve this, you will have to activate them before moving to the next room and then deactivate them in the next one again.
For some reason, activating these instances in the "room end" event didn't work for me (I might have made a mistake somewhere), but it does work if you activate them before you call the "room_goto" or any other function that moves the game to another room or restarts it. After you go to the next room, you can deactivate these instances again in the "room start" event.
Thanks for reading, you can download this project by clicking the link at the top of this thread. I hope you find this useful
~ECEngineering
Target Platform: Windows / All
Download: here
Built-in data structures are still more efficient than this method. It's purpose is to let you create your own custom data structures that do not exist in GameMaker.
This tutorial should help you create your own data structures with ease. As an example, I will be creating my own custom list. If you are not familiar with the term, OOP stands for Object Oriented Programming.
First thing you will have to do is create two scripts. One will create an instance of a "class", and the other one will delete it.
Setting everything up
First, let's create a "new" script that will create an instance of our class/object:
Script: new
Code:
///new(class name)
var tmp = instance_create(0,0,argument0);
instance_deactivate_object(tmp);
return tmp;
This way of creating objects is incredibly optimized as it only takes up memory. I've tested it by creating 100000 objects this way and it didn't affect performance at all.
Now, let's write the "delete" script that will free our instance from the memory once we don't need it anymore.
Script: delete
Code:
///delete(obj)
var object = argument0;
instance_activate_object(object);
with(object) instance_destroy();
Now, we have everything that we need to work with OOP, so we can begin creating our own data structures!
Creating data structures
Before we start creating our own data structures, I want to address a few things. It is possible to have something similar to class-functions, but in order to do that, you would have to activate the instance, call all the functions that you want to call, and then deactivate it again. As this usually looks very "ugly", I will be doing it the same way YoYoGames did it. We will create scripts that will take the reference of the instance as an argument in the similar manner as the built-in GM:S data structure functions do (ds_list_size(id)).
First thing we'll have to do is create two objects. We'll call them "cls_node" and "cls_list". The image below ilustrates the concept of lists.
The list consists of a chain of nodes that have two fields. One field holds their value, while the other one is holding the reference to the next node in the chain.
We can now write this code in the create event of the "cls_node":
cls_node Create Event:
Code:
data = undefined;
next = undefined;
That's it for the "cls_node" object. Now, we will be working on our "cls_list" object. If you take a look at the image above again, you will notice that there is something called "head" pointing to the first node in the list. That "head" is the list (well, at least the minimum you need in order to create it). In order to optimize our list, beside this "head" field in the list, we will add two more fields. First one will be "tail" which will always point on the last element so we don't have to iterate through the whole list when adding new values to it's top, and the second one will be "length" which will hold the length of the list so we don't have to iterate and count each time the request for it's size has been sent. We will put this in "cls_list" create event:
cls_list Create Event:
Code:
head = undefined;
tail = undefined;
length = 0;
The last thing we'll have to do is create some functions for our list. As I already said, you can create in-class functions and call them directly from the object by activating it and using "with" to call the function, but we will not be doing it because it is not convenient.
I will give you examples on some functions but not all of them as this is not the tutorial on lists in particular, but on creating your own data structures in general.
Script: list_size
Code:
///list_size(id)
return argument0.length;
Script: list_add
Code:
///list_add(id, value)
var list = argument0;
var n = new(cls_node); //create a new node
n.data = argument1; //write data to it
//if the list is not empty, set the last element to point to this one (as it will become the tail now)
if(list.length>0)
list.tail.next = n;
list.tail = n; //our new node will now become the tail
//if the list is emty, this will be the first element - the head
if(list.length==0)
list.head = n;
//increase the list length variable
list.length++;
Script: list_find_value
Code:
///list_find_value(id, index)
var list = argument0;
var index = argument1;
if(list.length > index){ //if index is inside the list
//iterating through nodes to get to the desired one
var tmp = list.head;
for(var i = 0; i < index; i++)
tmp = tmp.next;
return tmp.data; //returning the node data
}else show_message("List Error: Index is outside of the list");
Script: list_insert
Code:
///list_insert(id, position, value)
var list = argument0;
var position = argument1;
var value = argument2;
if(position<list.length){
var tmp = list.head;
for(var i = 0; i < position-1; i++) //iterate until reaching the previous node
tmp = tmp.next;
var n = new(cls_node);
n.data = value;
n.next = tmp.next; //set the next value to the node currently occupying this index
tmp.next = n; //set the next value of the previous node to our new one
list.length++;
}else if(position==list.length) //if inserting to the end, call the add function
list_add(list,data);
else show_message("List Error: Index is outside of the list");
Script: list_free
Code:
///list_free(id)
var list = argument0;
var iterator = list.head;
var tmp = iterator;
//iterates through all nodes and deletes each one
for(var i = 0; i < list.length; i++){
iterator = iterator.next;
delete(tmp);
tmp = iterator;
}
//deletes the list
delete(list);
Using our Data Structures in game
We can now use these data structures from anywhere in the code. Here is the example of how you may use this in your game:
Code:
var list = new(cls_list);
show_message(list_size(list));
for(var i = 0; i < 10; i++)
list_add(list,i+5);
show_message(list_size(list));
var s = "";
for(var i = 0; i < list_size(list); i++)
s+=string(list_find_value(list,i))+" ";
show_message(s);
list_insert(list,5,1000);
var s = "";
for(var i = 0; i < list_size(list); i++)
s+=string(list_find_value(list,i))+" ";
show_message(s);
list_free(list);
Making our Data Structures persistent:
You may notice that ticking the "persistent" box in the object editor isn't enough to make our structures persistent. GameMaker:Studio does not allow deactivated instances to move through rooms even though they are persistent. To solve this, you will have to activate them before moving to the next room and then deactivate them in the next one again.
For some reason, activating these instances in the "room end" event didn't work for me (I might have made a mistake somewhere), but it does work if you activate them before you call the "room_goto" or any other function that moves the game to another room or restarts it. After you go to the next room, you can deactivate these instances again in the "room start" event.
Thanks for reading, you can download this project by clicking the link at the top of this thread. I hope you find this useful
~ECEngineering
Last edited by a moderator: