2.3.1 Array Problem

obscene

Member
I have a ton of nested arrays inside a array called menu_main. Previously, If I did this...
Code:
menu=menu_main;
...and then changed menu_main, menu was also changed because it was a "pointer" (I guess that's the right term?)

Now, in 2.3, if I change menu_main, menu is not changed leaving me to believe menu is a copy of the original array. Correct?

I don't know if I have a question, other than do I understand this correctly and is there any way to force GM to treat menu as a pointer as it previously did?
 

Roldy

Member
I have a ton of nested arrays inside a array called menu_main. Previously, If I did this...
Code:
menu=menu_main;
...and then changed menu_main, menu was also changed because it was a "pointer" (I guess that's the right term?)

Now, in 2.3, if I change menu_main, menu is not changed leaving me to believe menu is a copy of the original array. Correct?

I don't know if I have a question, other than do I understand this correctly and is there any way to force GM to treat menu as a pointer as it previously did?
Most likely you will need to pay attention to accessors. If you index into an array without using the proper accessor then the array may be copied and modified instead of working as a reference. Review the manual for accessors, specially the array section: https://manual.yoyogames.com/#t=Gam...ssors.htm&rhsearch=accessor&rhhlterm=accessor

If this is not your issue then provide sample code that reproduces the issue so people can help you.
 

samspade

Member
I have a ton of nested arrays inside a array called menu_main. Previously, If I did this...
Code:
menu=menu_main;
...and then changed menu_main, menu was also changed because it was a "pointer" (I guess that's the right term?)

Now, in 2.3, if I change menu_main, menu is not changed leaving me to believe menu is a copy of the original array. Correct?

I don't know if I have a question, other than do I understand this correctly and is there any way to force GM to treat menu as a pointer as it previously did?
They're still references/pointers. But arrays have copy on write in most cases where there is more than one reference to the same array if you don't use the array accessor. This can be true even when the array is not being passed as an argument to a function.
 
What I like do these days is make the "bottom layer" of the array a struct.
When you loop through it, you can call, for example,
Code:
_struct = array[_i][_j];
to get any variable in there, and use other.variable_to_set to set it on the calling object if you use with(_struct){}
I find it's way less of a hassle to write to structs and read the debugger, while maintaining the efficiency and simplicity of arrays for looping.

For example, on a grid overworld map, the array map_cell[gridX][gridY] would point to a struct with all the cell variables. Then if for example you build a road in a cell, just toggle a has_road flag in the struct of that specific cell.
Hope that helps and made sense.
 
Last edited:

obscene

Member
Yeah none of this is making sense in regard to what I'm doing. It's like this...

In my menu object, I create a bunch of arrays that represent settings. For example.

Code:
        menu_settings_gamepad_vibration[0]=scr_text_get_string(text.settings_gamepad_vibration); // Name of setting
        menu_settings_gamepad_vibration[1]=scr_settings_gamepad_vibration_set; // Script that changes the setting
        menu_settings_gamepad_vibration[2]=global.settings_gamepad_vibration; // Variable that holds the setting
        menu_settings_gamepad_vibration[3]=off; // Available options
        menu_settings_gamepad_vibration[4]=on;
These settings are inside menu arrays, for example...

Code:
        menu_settings_gameplay[0]=scr_text_get_string(text.settings_gameplay); // Name of menu
        menu_settings_gameplay[1]=menu_settings_gameplay_hud;
        menu_settings_gameplay[2]=menu_settings_gameplay_damage_text; // The above array
        menu_settings_gameplay[3]=menu_settings_gameplay_reset_default;
And that's inside another menu array...

Code:
        menu_settings[0]=scr_text_get_string(text.settings); // Parent menu of the above
        menu_settings[1]=menu_settings_audio;
        menu_settings[2]=menu_settings_gamepad;
        menu_settings[3]=menu_settings_gameplay; // The above array (that also contains the setting array)
        menu_settings[4]=menu_settings_graphics;
        menu_settings[5]=menu_settings_language;
And so on. When I enter into a submenu, or back out of one, basically I keep track of what menu is current with something like this...

Code:
        current_menu=menu_settings_graphics;
The trick is when I change a setting, like global.settings_gamepad_vibration changing from 0 to 1, I need to update the menu so when it draws to screen the setting shows the new value. Before, in GMS 2.25, I just re-initialized my menu again. ie, all the code above is in a user event and I just run it again. The entire menu is rebuilt. This way, this line runs again....

Code:
        menu_settings_gamepad_vibration[2]=global.settings_gamepad_vibration;
And now when I loop through my array in the draw event, it shows the correct value for vibration.

But like I said, it used to work in 2.25. But now in 2.3 the original menu is updated correctly, but current_menu is retaining an old copy. The setting gets changed, but drawing the current menu draws the old setting. And accessors has nothing to do with it as far as I can tell, because you can't put an accessor in this line of code. And also accessors for arrays seems to be a script-only deal anyway so it's irrelevant.

@Tyg, your suggestion of current_menu=@menu_settings_graphics; isn't valid code at all.

So I think my entire way of doing menus is obsolete.
 

Tyg

Member
just a thought if you use enums
enum Menu_Setttings {gameplay, audio, graphics, gamepad, ...}
then Menu_Settings[audio]
or if audio is an array
or Menu_settings[audio][2]
or audio could also be an enum
enum audio {volume, max_volume, songlist, ...}
then you could use Menu_Settings[audio][max_volume]

a good example of this is in the FBX reader by alsekov in the fbx dll
 

Tyg

Member
sorry you would access the last one as Menu_Settings[audio.max_volume] i believe
 
@obscene that's weird, I do all my menus like that and even in 2.3, It's fine. Ok, I had a ton of other bugs like debugger not updating, events not running and some strange stuff, but my array navigation using a current_menu like that still works fine for me.
At that point I would just put a breakpoint when you do current_menu_item++, and run the game line by line. You'll be able to know exactly why and where it does what it does.
 

xDGameStudios

GameMaker Staff
GameMaker Dev.
Yeah none of this is making sense in regard to what I'm doing. It's like this...

In my menu object, I create a bunch of arrays that represent settings. For example.

Code:
        menu_settings_gamepad_vibration[0]=scr_text_get_string(text.settings_gamepad_vibration); // Name of setting
        menu_settings_gamepad_vibration[1]=scr_settings_gamepad_vibration_set; // Script that changes the setting
        menu_settings_gamepad_vibration[2]=global.settings_gamepad_vibration; // Variable that holds the setting
        menu_settings_gamepad_vibration[3]=off; // Available options
        menu_settings_gamepad_vibration[4]=on;
These settings are inside menu arrays, for example...

Code:
        menu_settings_gameplay[0]=scr_text_get_string(text.settings_gameplay); // Name of menu
        menu_settings_gameplay[1]=menu_settings_gameplay_hud;
        menu_settings_gameplay[2]=menu_settings_gameplay_damage_text; // The above array
        menu_settings_gameplay[3]=menu_settings_gameplay_reset_default;
And that's inside another menu array...

Code:
        menu_settings[0]=scr_text_get_string(text.settings); // Parent menu of the above
        menu_settings[1]=menu_settings_audio;
        menu_settings[2]=menu_settings_gamepad;
        menu_settings[3]=menu_settings_gameplay; // The above array (that also contains the setting array)
        menu_settings[4]=menu_settings_graphics;
        menu_settings[5]=menu_settings_language;
And so on. When I enter into a submenu, or back out of one, basically I keep track of what menu is current with something like this...

Code:
        current_menu=menu_settings_graphics;
The trick is when I change a setting, like global.settings_gamepad_vibration changing from 0 to 1, I need to update the menu so when it draws to screen the setting shows the new value. Before, in GMS 2.25, I just re-initialized my menu again. ie, all the code above is in a user event and I just run it again. The entire menu is rebuilt. This way, this line runs again....

Code:
        menu_settings_gamepad_vibration[2]=global.settings_gamepad_vibration;
And now when I loop through my array in the draw event, it shows the correct value for vibration.

But like I said, it used to work in 2.25. But now in 2.3 the original menu is updated correctly, but current_menu is retaining an old copy. The setting gets changed, but drawing the current menu draws the old setting. And accessors has nothing to do with it as far as I can tell, because you can't put an accessor in this line of code. And also accessors for arrays seems to be a script-only deal anyway so it's irrelevant.

@Tyg, your suggestion of current_menu=@menu_settings_graphics; isn't valid code at all.

So I think my entire way of doing menus is obsolete.
[PROBLEM]
When you create a reference of an array and edit it your original array stays the same and only the "copy" gets modifier.

[EXPLANATION]
There are four different array behaviour you need to understand.
1) Editing an array directly will edit the original array and consequently ALL the references.
GML:
var array1 = [1, 2, 3, 4, 5];
var array2 = array1;
array1[0] = "Hello";
show_debug_message(array1) // ["Hello", 2, 3, 4, 5];
show_debug_message(array2) // ["Hello", 2, 3, 4, 5];
2) Assigning an array to a new variable will just share the pointer to that array
GML:
var array1 = [1, 2, 3, 4, 5];
var array2 = array1;
show_debug_message(array1) // [1, 2, 3, 4, 5]; <- same pointer
show_debug_message(array2) // [1, 2, 3, 4, 5]; <- same pointer
3) Editing a reference to an array will only edit the reference and not the original
GML:
var array1 = [1, 2, 3, 4, 5];
var array2 = array1;
array2[0] = "Hello";
show_debug_message(array1) // [1, 2, 3, 4, 5];
show_debug_message(array2) // ["Hello", 2, 3, 4, 5];
4) This is similar to the third one, passing an array as an argument counts as making a reference to it.
GML:
function myFunc(array) {
    array[0] = "Hello";
}

var array1 = [1, 2, 3, 4, 5];
myFunc(array1);
show_debug_message(array1) // [1, 2, 3, 4, 5];
This last one happens because the "array" variable of the function is actually a reference to the array1, so in the backstage GMS does array = array1 and then passes the argument to the function. Every time you set a variable to an array that variable is given the pointer to the array, BUT as soon as you edit it.. the array gets copied and dereferenced from the original.
It was like this all the way back from GMS1.4 if I'm not mistaken, so this is NOT new to 2.3.

[ACCESSORS]
You probably heard of accessors before specially if you used ds_lists, ds_maps, ds_grids. Those are symbols that allow for quick edit of entries in the respective data structures
GML:
myList[| 0] = 12; // the accessor is -> |
myMap[? "name"] = "value"; // the accessor is -> ?
myGrid[# 1, 2] = true // the accessor is -> #

[SOLUTION]
What many people don't know is there is a special accessor for arrays too, that apart from allowing quick access to values. The array accessors stops GMS from copying the original array and instead makes an in-place edit.
The array accessor is "@" (at symbol)
So whenever you want to edit (when writing) the original array instead of copying it you just need to use:
GML:
var array1 = [1, 2, 3, 4, 5];
var array2 = array1;
array2[@ 0] = "Hello";
show_debug_message(array1) // ["Hello", 2, 3, 4, 5]; <- same pointer
show_debug_message(array2) // ["Hello", 2, 3, 4, 5]; <- same pointer

[NOTE]
The array accessor allows for an edit-in-place so as you might have guessed you don't need to use it when reading from an array;
GML:
var array1 = [1, 2, 3, 4, 5];
var value = array1[@ 0] // this is not needed and as far as I know carries some overhead.
 
Last edited:

Tyg

Member
I know i am having problems when the name of the input varible argument0 and the the return variable have the same name especially with matrices and you multiply the matrix (which is basically an array) , that used to work but now it gets confused between the argument0 (which should be local to the function) and the return var. So i pull the input var right away. was even going buggy when renaming a file in the ide. I found that the new update to 536 solved alot of array issues. I just find that the enums run more smoothly and are clearer to understand than deep nesting arrays and thats why i suggested it ...good luck
 

Tyg

Member
[PROBLEM]
When you create a reference of an array and edit it your original array stays the same and only the "copy" gets modifier.

[EXPLANATION]
There are four different array behaviour you need to understand.
1)
GML:
var array1 = [1, 2, 3, 4, 5];
array1[0] = "Hello";
show_debug_message(array1) // ["Hello", 2, 3, 4, 5];
2)
GML:
var array1 = [1, 2, 3, 4, 5];
var array2 = array1;
show_debug_message(array1) // [1, 2, 3, 4, 5];
show_debug_message(array2) // [1, 2, 3, 4, 5]; <- same pointer
3)
GML:
var array1 = [1, 2, 3, 4, 5];
var array2 = array1;
array2[0] = "Hello";
show_debug_message(array1) // [1, 2, 3, 4, 5];
show_debug_message(array2) // ["Hello", 2, 3, 4, 5];
4) This is similar to the third one:
GML:
function myFunc(array) {
    array[0] = "Hello";
}

var array1 = [1, 2, 3, 4, 5];
myFunc(array1);
show_debug_message(array1) // [1, 2, 3, 4, 5];
This last one happens because the "array" variable of the function is actually a reference to the array1, so in the backstage GMS does array = array1 and then passes the argument to the function. Every time you set a variable to an array that variable is given the pointer to the array, BUT as soon as you edit it.. the array gets copied and dereferenced from the original.
It was like this all the way back from GMS1.4 if I'm not mistaken, so this is NOT new to 2.3.

[ACCESSORS]
You probably heard of accessors before specially if you used ds_lists, ds_maps, ds_grids. Those are symbols that allow for quick edit of entries in the respective data structures
GML:
myList[| 0] = 12; // the accessor is -> |
myMap[? "name"] = "value"; // the accessor is -> ?
myGrid[# 1, 2] = true // the accessor is -> #

[SOLUTION]
What many people don't know is there is a special accessor for arrays too, that apart from allowing quick access to values. The array accessors stops GMS from copying the original array and instead makes an in-place edit.
The array accessor is "@" (at symbol)
So whenever you want to edit (when writing) the original array instead of copying it you just need to use:
GML:
var array1 = [1, 2, 3, 4, 5];
var array2 = array1;
array2[@ 0] = "Hello";
show_debug_message(array1) // ["Hello", 2, 3, 4, 5]; <- same pointer
show_debug_message(array2) // ["Hello", 2, 3, 4, 5]; <- same pointer

[NOTE]
The array accessor allows for an edit-in-place so as you might have guessed you don't need to use it when reading from an array;
GML:
var array1 = [1, 2, 3, 4, 5];
var value = array1[@ 0] // this is not needed and as far as I know carries some overhead.
Thank you, you explained that very well :)
 

TailBit

Member
I tested the method OP described .. where the original array was changed after pointer was made, but it seem to work just fine:
GML:
var array1 = [1, 2, 3, 4, 5];
var array2 = [0,0,array1];
var array3 = array2[2];

array2 = null; // even after clearing everything in array 2, array3 still keeps its pointer
array1[0] = "Hello";

show_debug_message(array1) // ["Hello", 2, 3, 4, 5];
show_debug_message(array3) // ["Hello", 2, 3, 4, 5]; <- same pointer
So everything seems like it should work

EDIT: yeah, I just meant to clear the array connection for array2 .. but it should be garbage collected when it doesn't have a connection .. so in the end it would clear it.
 
Last edited:
  • Dislike
Reactions: Tyg

xDGameStudios

GameMaker Staff
GameMaker Dev.
I tested the method OP described .. where the original array was changed after pointer was made, but it seem to work just fine:
GML:
var array1 = [1, 2, 3, 4, 5];
var array2 = [0,0,array1];
var array3 = array2[2];

array2 = null; // even after clearing everything in array 2, array3 still keeps its pointer
array1[0] = "Hello";

show_debug_message(array1) // ["Hello", 2, 3, 4, 5];
show_debug_message(array3) // ["Hello", 2, 3, 4, 5]; <- same pointer
So everything seems like it should work
I want to make a comment on the sentence you said:

"even after clearing everything in array 2, array3 still keeps its pointer"

setting array2 to undefined or null (whatever that might be in your context) doesn't clear everything in the array it just dereferences the variable array2 so it doesn't point to the array anymore. The array still exists.

Now that we put that inconsistency aside.
Lets look at the code you just sent.

GML:
var array1 = [1, 2, 3, 4, 5];
var array2 = array1;
array1[0] = "hello"; // <- here you are editing the original
show_debug_message(array1); // ["hello", 2, 3, 4, 5]
show_debug_message(array2); // ["hello", 2, 3, 4, 5]
This is an example similar to the array behaviour number (1) editing the original array will result in a edit on the array itself... so ALL the references will reflect that change.

That is not the same as
GML:
var array1 = [1, 2, 3, 4, 5];
var array2 = array1;
array2[0] = "hello"; // <- here you are editing the reference
show_debug_message(array1); // [1, 2, 3, 4, 5]
show_debug_message(array2); // ["hello", 2, 3, 4, 5]
This is an example similar to the array behaviour number (3) editing the referenced array will result in copy-and-edit on the array itself... so the original will stay the same.
 
Last edited:

obscene

Member
Well. Thanks for all the replies. I only know one thing. I'm redoing my entire menu system and I'm not using arrays. Maybe all this stuff makes sense to you guys somehow but not to me. I've did a search and replace for every damn instance of [ and replaced it with [@ and no difference. That was probably dumb. I'm probably dumb. But to hell with this problem. I miss 2.2.5. Worked fine then and it made sense. What's really annoying here is that I'm literally not changing anything in this array. It only gets refreshed by the exact same code that created it, changing only the one variable of the setting that was changed. It's dirt simple. It worked before. It's trash now. Time for a redo and I'll ds_lists since they work rationally.
 
Last edited:

xDGameStudios

GameMaker Staff
GameMaker Dev.
@obscene, Replicate that same bug in a small project with just two or three arrays and send it to me.. so I can explain what the problem is. If is not working than it is something you are doing wrong... because nothing changed with arrays so far... everything is the way it was. Just a couple of functions were added.
 
Last edited:

Granderrota

Member
Hi. Excuse me; I am trying to learn q-learning using GML. I have this matrix in arduino, what do you think is the best way to pass it to GML?

float R[16][4] = {
{ 0, -1, 0, -1},
{-1, -1, 0, 0},
{-1, -1, 0, 0},
{-1, -1, -1, 0},
{ 0, 0, 0, -1},
{-1, 0, 0, 0},
{-1, 0, 0, 0},
{-1, 0, -1, 0},
{ 0, 0, 0, -1},
{-1, 0, 0, 0},
{-1, 0, 0, 0},
{-1, 0, -1, 0},
{-1, 0, 0, -1},
{-1, -1, 0, 0},
{-1, -1, 1000,0},
{-1, 0, -1, 0}};

Thank you very much
 

chamaeleon

Member
float R[16][4] = {
{ 0, -1, 0, -1},
{-1, -1, 0, 0},
{-1, -1, 0, 0},
{-1, -1, -1, 0},
{ 0, 0, 0, -1},
{-1, 0, 0, 0},
{-1, 0, 0, 0},
{-1, 0, -1, 0},
{ 0, 0, 0, -1},
{-1, 0, 0, 0},
{-1, 0, 0, 0},
{-1, 0, -1, 0},
{-1, 0, 0, -1},
{-1, -1, 0, 0},
{-1, -1, 1000,0},
{-1, 0, -1, 0}};
Just about the same.
GML:
R = [
[ 0, -1, 0, -1],
[-1, -1, 0, 0],
[-1, -1, 0, 0],
[-1, -1, -1, 0],
[ 0, 0, 0, -1],
[-1, 0, 0, 0],
[-1, 0, 0, 0],
[-1, 0, -1, 0],
[ 0, 0, 0, -1],
[-1, 0, 0, 0],
[-1, 0, 0, 0],
[-1, 0, -1, 0],
[-1, 0, 0, -1],
[-1, -1, 0, 0],
[-1, -1, 1000,0],
[-1, 0, -1, 0]];

show_debug_message(R);
Code:
[ [ 0,-1,0,-1 ],[ -1,-1,0,0 ],[ -1,-1,0,0 ],[ -1,-1,-1,0 ],[ 0,0,0,-1 ],[ -1,0,0,0 ],[ -1,0,0,0 ],[ -1,0,-1,0 ],[ 0,0,0,-1 ],[ -1,0,0,0 ],[ -1,0,0,0 ],[ -1,0,-1,0 ],[ -1,0,0,-1 ],[ -1,-1,0,0 ],[ -1,-1,1000,0 ],[ -1,0,-1,0 ] ]
Unless "pass to GML" means transferring data from an arduino to a GMS program, in which case you will need an extension, presumably (and you might have to make your own). And this should have been its own thread, not a reply to an unrelated problem if that is the case.
 

Granderrota

Member
Thanks for such a quick response.
I want to make an object in GM that simulates being this simple robot (web attachment), and then go on doing increasingly complex q-learning things in GML.

Q-learning con Arduino: Crawling Robot (Español) | by Erick M. Sirpa | Planeta Chatbot : todo sobre los Chat bots, Voice apps e Inteligencia Artificial

My amateur fault. Thanks again
R=[16][4] = [
[ 0, -1, 0, -1],
[-1, -1, 0, 0],
[-1, -1, 0, 0],
[-1, -1, -1, 0],
[ 0, 0, 0, -1],
[-1, 0, 0, 0],
[-1, 0, 0, 0],
[-1, 0, -1, 0],
[ 0, 0, 0, -1],
[-1, 0, 0, 0],
[-1, 0, 0, 0],
[-1, 0, -1, 0],
[-1, 0, 0, -1],
[-1, -1, 0, 0],
[-1, -1, 1000,0],
[-1, 0, -1, 0]];
 
Last edited:

andev

Member
Hi. Excuse me; I am trying to learn q-learning using GML. I have this matrix in arduino, what do you think is the best way to pass it to GML?

float R[16][4] = {
{ 0, -1, 0, -1},
{-1, -1, 0, 0},
{-1, -1, 0, 0},
{-1, -1, -1, 0},
{ 0, 0, 0, -1},
{-1, 0, 0, 0},
{-1, 0, 0, 0},
{-1, 0, -1, 0},
{ 0, 0, 0, -1},
{-1, 0, 0, 0},
{-1, 0, 0, 0},
{-1, 0, -1, 0},
{-1, 0, 0, -1},
{-1, -1, 0, 0},
{-1, -1, 1000,0},
{-1, 0, -1, 0}};

Thank you very much
Should this not be its own thread lol?
 
  • Like
Reactions: Tyg

Tyg

Member
Yes it should
Should this not be its own thread lol?
i made a text parser if you want to read your data from a text file you can use that as a base
 
Top