• 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!

GameMaker [@Solved]3D arrays

Kahrabaa

Member
Hello I need to use 3d arrays for a simple animation program I made storing Frame, Part and Value.

Right now I am using a script that lolslayer posted by using the first value of the array as 2, by jumping into higher values to reserve space for the extra dimension. From here
https://forum.yoyogames.com/index.php?threads/3d-array-workaround.3913/
Code:
///get_arr2
/// @param frame
/// @param part
var ax = argument0;                 //array x, start with 0
var ay = argument1;                 //array y, start with 0
var ly = maxParts;                 //length of the array columns

return ax*ly + ay;
Works great doing this
arr[ get_arr2 ( x, y) , z ] = value

But, within the script, the addition and multiplication in the end is costing heavy processing since i'm looping alot and there for need to access alot. I am looking for a more efficient way.
I kind of understand how nested arrays works but I cant seem to implement them into simplified set_arr3 and get_arr3 scripts.

Thank you for any suggestions!
 
Last edited:

Binsk

Member
Code:
/// This:
arr[get_arr2(x, y), z] = value

// Is the same as this:
arr[x][y][z] = value
HOWEVER, GameMaker does not *yet* support chaining accessors (aka, putting the []'s next to eachother). The concept as to how the data is stored is the same as shown above, but until they add accessors you can make a script like this:
Code:
///get_xyz(array, x, y, z)
var _y = argument0[argument1]; // Grab the [y] portion, store in _y
var _z = _y[argument2]; // Grab the [z] portion, store in _z
var _value = _z[argument3]; // Finally, grab the value from z
return _value;

///set_xyz(array, x, y, z, value)
var _y = argument0[argument1]; // Grab the [y] portion, store in _y
var _z = _y[argument2]; // Grab the [z] portion, store in _z
_z[@ argument3] = argument4; // Set the value into the ORIGINAL z array (using @ accessor)
return undefined;
Note for that set_xyz to script work, the array has to already be allocated to size since it is using the @ accessor to reset the value.

If you don't want to use the @ accessor then, after setting _z[argument3] = argument4, you will need to store z back into y, y back into x, then return x from the script and set your original array to the return value every time you modify the value.

E.g.,
Code:
// WITH the @ accessor:
set_xyz(arr, x, y, z, 10);

// WITHOUT the @ accessor (after you've modified the script):
arr = set_xyz(arr, x, y, z, 10);
 
Last edited:

Kahrabaa

Member
Code:
/// This:
arr[get_arr2(x, y), z] = value

// Is the same as this:
arr[x][y][z] = value
HOWEVER, GameMaker does not *yet* support chaining accessors (aka, putting the []'s next to eachother).
Looking forward to this!

the array has to already be allocated to size since it is using the @ accessor to reset the value.
What does this mean? Am I to prepare a 1D array with the length of the combined size of the 3D array (x*y*z)? I have no problem predefining the size of the array since accessors seems to remove unnecessary copying of arrays right? But it seems I am getting something wrong.
This is what I tried and am getting an error using the exact set and get scripts you provided.
Code:
arr[1000]=0; //Put I high value here just in case

var i=0;
repeat(5){
    var ii=0;
    repeat(5){
        var iii=0;
        repeat(5){

        //It is failing to set in the first step of the loop, at i=0 ii=0 and iii=0
        sa3(arr,i,ii,ii,irandom(10));

        iii+=1;
        }
    ii+=1;
    }
i+=1;
}

show_message(ga3(arr,3,5,3));
Code:
trying to index a variable which is not an array
 at gml_Script_sa3 (line 3) - var _z = _y[argument2];
Thank you!
 
Last edited:

Binsk

Member
When creating multi-dimensional arrays it's important to remember how they actually work under the hood.
When you have a variable you have some value stored in memory. When you have a 1D array what you have is a location of memory that starts a chunk of allocated data, which would then contain the values in the array. By specifying a number in square brackets, like array[10] you are saying "grab the point 10 spaces away from the location stored by array".

So what is a 2D array? It is a location to a block of data where each value in that block is another location to a different block of data. A 3D array is just one step deeper. All this to say that, since each of these values are pointing to different locations in memory simply forming a 1D array with the correct number of data pieces will not work because the first value pulled will be used as the location in memory for the second value. That obviously won't point to the right thing.

This is just a long-winded way of saying:
Instead of allocating arr to x * y * z spots, you need to manually allocate array x where each value in x should be a different array, y, which has been allocated where every value of y should be a different array, z, which has been allocated where each value is the actual value you wish to store. You need x * y arrays to store x * y * z values.

You can build all this in a couple for loops. When all these arrays are stored inside eachother you can then access them as explained via my scripts. The nice thing is is that if you ever need 4D, 5D, or more dimensions it is extremely easy to keep adding more once you get the basics of this implemented.
 

Kahrabaa

Member
Okay, this is what I tried but I get incorrect values when I read them. Did I misunderstand?
Code:
var xx,yy,zz,arrX,arrY,arrZ;
xx=0;
repeat(10){ //For each value in array X...
 
    yy=0;
    repeat(10){ //Prepare, for each value in array Y...
 
        zz=0;
        repeat(10){ //Prepare, for each value in array Z...
        arrZ[zz]="xx: "+string(xx)+" yy: "+string(yy)+" zz: "+string(zz);
        zz+=1;
        }
 
    arrY[yy]=arrZ; //Insert prepared Z array into each Y array
    yy+=1;
    }
 
arrX[xx]=arrY; //Insert prepared Y array into each X array
xx+=1;
}

//And reading

xx=0;
repeat(10){
    yy=0;
    repeat(10){
        zz=0;
        repeat(10){
        show_debug_message( ga3( arrX,xx,yy,zz ) );
       zz+=1;
        }
    yy+=1;
    }
xx+=1;
}
This the what is being read, as if the script is not cycling through xx and yy

xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9
xx: 9 yy: 9 zz: 0
xx: 9 yy: 9 zz: 1
xx: 9 yy: 9 zz: 2
xx: 9 yy: 9 zz: 3
xx: 9 yy: 9 zz: 4
xx: 9 yy: 9 zz: 5
xx: 9 yy: 9 zz: 6
xx: 9 yy: 9 zz: 7
xx: 9 yy: 9 zz: 8
xx: 9 yy: 9 zz: 9

EDIT:
Okay, it seems like the same array was being set into parent arrays so I was overwriting the values.
All I had to do was undefine the array variables to make them seperate. Like this

Code:
//Prepare 3D array
            var xx,yy,zz,arrY,arrZ;
            xx=0;
            repeat(frames){ //For each value in array x...

                arrY=undefined; //Undefine, to create a new array index
                yy=0;
                repeat(frameI[f,1]){ //Prepare, for each value in array y...

                    arrZ=undefined; //Undefine, to create a new array index
                    zz=0;
                    repeat(10){ //Prepare, for each value in array z...
                    arrZ[zz]=1;
                    zz+=1;
                    }
 
                arrY[yy]=arrZ; //Insert prepared z arrays into each y array
                yy+=1;
                }
 
            arrX[xx]=arrY; //Insert prepared y array into x array
            xx+=1;
            }
        }
Finally! Thank you so much Binsk for helping me understand this!! When I was most confused I didnt understand that a value in a array can hold the array index of another array. I thought it nested the array through a magical way similar to buffers by storing it all in 1D array and jumping between "blocks" of data.

Double Edit:
Sadly this did not improve the performance =( =(
It forced me to do more calls to access the 3d info and therefore making it worse.

This is before and after


But hey, I learned new things!
Peace out

Triple Edit:
Found a way to make it perform better!


Two of my array dimensions where dynamic and large, the third one was fixed 10 values so I could skip 3D arrays alltogether and instead, number name the variables.
value0[ frame, part ]=0;
value1[ frame, part ]=0;
value2[ frame, part ]=0;
value3[ frame, part ]=0;
etc.

I should have thought of this from the begginning xD
 
Last edited:
Top