• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Struct x/y coords?

Neptune

Member
If I have a function that finds an X,Y coordinate pair, can I return a struct containing the two values? (opposed to returning a string containing a ds_list or something.)
Any information is appreciated :)
 

Alice

Darts addict
Forum Staff
Moderator
Generally, you can, but you should be careful not to create too many of these at once - creating hundreds or thousands of structs each Step can have a serious performance impact when they need to be garbage-collected. If it's like single structs or tens being created each Step overall, you probably won't experience so much slowdown.

Now, if you e.g. had a fixed grid of structs containing x/y coordinates, and you return these structs instead, there shouldn't be as much overhead, because you return an existing entity instead of creating a new one. So e.g. if you had a grid of structs with properties like (x, y, type, name), and you need to find the first struct of a given type or name, you can just return that specific struct instead.
 

Neptune

Member
@Fanatrick Hey, so what would calling that look like?

@Alice Ok, so there is not a manual way to clean up structs? How do I signal that a struct is ready for cleanup?
 
Last edited:

Alice

Darts addict
Forum Staff
Moderator
@Alice Ok, so there is not a manual way to clean up structs? How do I signal that a struct is ready for cleanup?
As far as I can tell, the only way right now to signal that a struct is ready for cleanup is to remove whatever variable is holding it.
E.g. if you have an instance of obj_enemy with weapon_properties struct and you destroy the instance, the weapon_properties variable won't be referenced anymore, and garbage collector will clean it up.
There is also a "delete" keyword that allows removing specific fields. So e.g. if you have a struct with player1/player2/player3 fields, and you do "delete player.player3", then player3 won't be referenced anymore and will be marked for garbage collection.

Or so I think, but you might want to consult the manual for that. At any rate, I don't think there's a way to manually destroy struct, the best you can do is drop all the points referencing it (instances, structs, data structures, arrays...) and then wait for the garbage collector to clean it up.
 

samspade

Member
@Fanatrick Hey, so what would calling that look like?

@Alice Ok, so there is not a manual way to clean up structs? How do I signal that a struct is ready for cleanup?
Fanatrick's version is simply a function that returns a struct and would be no different in use than:

GML:
function vec2(_x, _y) {
    return [_x, _y];
}
Except that it would come out as a struct. Depending upon what your actual function looks like you could do either:

GML:
function your_function() {
    ...your stuff
    return { x : _x, y : _y}
}

function your_function() {
    ...your stuff
    return vec2(_x, _y);
}
Where _x and _y are values from earlier in your function's code. You could also use a constructor. If you want a basic 2d vector constructor I have one here: https://forum.yoyogames.com/index.php?threads/basic-vector-functions-in-2-3-proper-way.76549/. If you used a constructor, you would need the keyword new before the function call.

You can, but are not required to, use delete with structs. I'm not sure how much faster this is than letting the garbage collector take care of it normally. I think regardless of use structs are currently slower than arrays (hopefully they'll fix this at some point).
 

Neptune

Member
@Alice Hmm I see, thankyou!
I wonder if my_struct = noone; would signal for cleanup, or cause a memory leak 😂

@samspade Thanks for info! Did not know you could just return an array... Hm.
So what does this look like OUTside of the function, say in a step event where the function is called?

This is what I do:

GML:
var coords = scr_find_tile(params);
if coords != noone
{
    var coord_list = ds_list_create(); ds_list_read(coord_list,coords);
    var xx = coord_list[| 0];
    var xy = coord_list[| 1];
    ds_list_destroy(coord_list); coord_list = noone;
}
Returning an actual structure, array, list etc is news to me... So a detailed / simple example is much appreciated.
 
Last edited:

samspade

Member
Hmm I see, thankyou!
I wonder if my_struct = noone; would signal for cleanup, or cause a memory leak 😂
As far as I know, structs cannot cause a memory leak (assuming gc is on) but the manual says delete is more efficient clean up: "By default, structs with no further references in code will be garbage collected automatically in the steps following their use, but it is good practice to use this operator to flag them explicitly for the garbage collector to remove from memory at the very start of the following step, freeing the memory quickly and more efficiently." I'm not sure how much better it is though.
 

samspade

Member
So what does this look like OUTside of the function, say in a step event where the function is called?
I'm not sure what you mean by this. Do you mean how do you use an array or struct returned by a function? If that is the case it would look like this assuming that your_function returned either a struct or array containing two values, x and y, where they are either named that, in the case of a struct or x is the first and y is the second value in the returned array:

GML:
a_variable = your_fucntion();

//example use if a struct
x = a_variable.x;

//example use if an array
x = a_variable[0];
 

Alice

Darts addict
Forum Staff
Moderator
So I thought arrays were removed from 2.3, or was it just the array functions or something?
What was removed was 2D arrays, because now you can nest arrays indefinitely, and access them via chained array accessor, rather than 2D-array accessor.

So you can now do var _array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];, and then access it as var _arrayValue = _array[1][2];.
As in, select 1st array item from _array (i.e. [4, 5, 6]), and from that item select 2nd item (i.e. 6); of course 0-based indices apply here.

Earlier, you would use _array[1, 2] syntax instead (not sure if it would work correctly for this particular array declaration).
 

rytan451

Member
Anonymous structs (i.e., structs that are defined without a constructor) can actually be slower than structs defined using a constructor. Because you're just returning an (x, y) pair, you may as well define a constructor in a script that creates a 2D vector.

For example:

GML:
function Vector2(_x, _y) constructor {
  x = _x;
  y = _y;
}
If you need some vector math, then you may also want to add a few static members that include functions to do the vector math. I've actually written a fully-fledged 2D vector implementation in pure GML, which you can find here, or through the link in my sig.
 
Top