GameMaker Tilemap Array Loses Place when Sprite Based Instances in Room

There seems to be a bug with tilemap ids, but I'm not sure. When I add visible instances with sprites to my room I get the name of the background instead of a tilemap in spite of the fact that I use "if layer_get_element_type(a) == layerelementtype_tilemap" before adding the name and id of the tilemap to arrays. If I add more than 3 visible instances with sprites it errors and acts like the array is out of bounds. If I remove the background color layer then instead of the background name "Backgrounds_1" showing up as if it's a tilemap, the number of layer slots in my tilemap_name_list[tilemap_layers] array (and other arrays) are reduced, but it still starts with "Sun." The array goes in reverse order to give me furthest layer first, but I still get the problem the other way too.

My layers are:
Instances,Grass,Clouds, Sun,Background_1
(The middle 3 are tilemaps.)

Tilemap_Find_obj



Create:

//Get the tile layer arrays from the room

a = layer_get_all()
i=array_length_1d(a)-1

tilemap_layers=0

while (i >0)

{
if layer_get_element_type(a [ i ] ) == layerelementtype_tilemap

{
tilemap_id_list[tilemap_layers]=layer_tilemap_get_id(i)
tilemap_name_list[tilemap_layers]=layer_get_name(i)

tilemap_x_list[tilemap_layers]=tilemap_get_x(i)
tilemap_y_list[tilemap_layers]=tilemap_get_y(i)

tilemap_tile_w_list[tilemap_layers]=tilemap_get_tile_width(i)
tilemap_tile_h_list[tilemap_layers]=tilemap_get_tile_height(i)

//how many tilemap layers we have
tilemap_layers+=1
}
i+=-1
}
Draw GUI:

//Drawing the results.

draw_text(0,0,"tilemap id " + string(tilemap_id_list))
draw_text(0,20,"tilemap name " + string(tilemap_name_list))
draw_text(0,40,"tilemap layers " + string(tilemap_layers))

draw_text(0,60,"tilemap x list " + string(tilemap_x_list))
draw_text(0,80,"tilemap y list " + string(tilemap_y_list))



Empty_Sprite_Obj

visible=true


Testing It

1.Works fine if you don't add sprite based instances.
2. Place the 1 Empty_Sprite_Obj in the room in the instance layer. Array is in wrong place.
3. Add 4 Empty_Sprite_Obj intances total, and you get an out of bounds error.

Download at
https://www.dropbox.com/s/p551bpgaolizoio/Tilemap Error.yyz?dl=0


Images below contain some extra variables before I narrowed down where things were going wrong, The tilemap names, and ids are the problem in the images.
Works With No Visible Sprite Instance.jpg Tilemap Error, Includes Background.jpg Tilemap Error Outside Array.jpg

Is this a bug, or is there something I can do to fix it in my game, and if so what? If it is a bug is there any workaround?
 
Last edited:

samspade

Member
There seems to be a bug with tilemap ids, but I'm not sure. When I add visible instances with sprites to my room I get the name of the background instead of a tilemap in spite of the fact that I use "if layer_get_element_type(a) == layerelementtype_tilemap" before adding the name and id of the tilemap to arrays. If I add more than 3 visible instances with sprites it errors and acts like the array is out of bounds. If I remove the background color layer then instead of the background name "Backgrounds_1" showing up as if it's a tilemap, the number of layer slots in my tilemap_name_list[tilemap_layers] array (and other arrays) are reduced, but it still starts with "Sun." The array goes in reverse order to give me furthest layer first, but I still get the problem the other way too.

My layers are:
Instances,Grass,Clouds, Sun,Background_1
(The middle 3 are tilemaps.)

Tilemap_Find_obj

Create:
//Create an array of the tile layers

a = layer_get_all()
i=array_length_1d(a)-1

tilemap_layers=0

while (i >0)
{
if layer_get_element_type(a) == layerelementtype_tilemap
{
tilemap_id_list[tilemap_layers]=layer_tilemap_get_id(i)
tilemap_name_list[tilemap_layers]=layer_get_name(i)

tilemap_x_list[tilemap_layers]=tilemap_get_x(i)
tilemap_y_list[tilemap_layers]=tilemap_get_y(i)

tilemap_tile_w_list[tilemap_layers]=tilemap_get_tile_width(i)
tilemap_tile_h_list[tilemap_layers]=tilemap_get_tile_height(i)

tilemap_layers+=1
}
i+=-1
}
Draw GUI:
//Drawing the results.

draw_text(0,0,"tilemap id " + string(tilemap_id_list))
draw_text(0,20,"tilemap name " + string(tilemap_name_list))
draw_text(0,40,"tilemap layers " + string(tilemap_layers))

draw_text(0,60,"tilemap x list " + string(tilemap_x_list))
draw_text(0,80,"tilemap y list " + string(tilemap_y_list))



Empty_Sprite_Obj

visible=true


Testing It

1.Works fine if you don't add sprite based instances.
2. Place the 1 Empty_Sprite_Obj in the room in the instance layer. Array is in wrong place.
3. Add 4 Empty_Sprite_Obj intances total, and you get an out of bounds error.

Download at
https://www.dropbox.com/s/p551bpgaolizoio/Tilemap Error.yyz?dl=0


Is this a bug, or is there something I can do to fix it in my game, and if so what? If it is a bug is there any workaround?
I don't use these function, but looking at your code, and reading the manual, this line "layer_get_element_type(a)" seem almost certain to be wrong since a is an array, but you aren't referencing it as an array. I would also recommend stepping through this code in the debugger. As that will probably show you immediately what the problem is.

While I don't see how this would cause a problem, why use a while loop here when a for loop would work just as well? If you are going to use a while loop i -= 1 works just as well as i += -1 and is a little easier to read (which is important for when you want to scan through your code or post it on the forum for someone else to do). Along the same lines, looks like your formatting got messed up. Which makes it harder to read and also want to help. It would also be a good practice to include spaces around your equal signs for the same reason.
 
I don't use these function, but looking at your code, and reading the manual, this line "layer_get_element_type(a)" seem almost certain to be wrong since a is an array, but you aren't referencing it as an array. I would also recommend stepping through this code in the debugger. As that will probably show you immediately what the problem is.

While I don't see how this would cause a problem, why use a while loop here when a for loop would work just as well? If you are going to use a while loop i -= 1 works just as well as i += -1 and is a little easier to read (which is important for when you want to scan through your code or post it on the forum for someone else to do). Along the same lines, looks like your formatting got messed up. Which makes it harder to read and also want to help. It would also be a good practice to include spaces around your equal signs for the same reason.
When I posted it took the [ i ] out of layer_get_element_type(a [ i ] ) unless I added spaces into it. I fixed that now and the indention removal, and didn't realize it had done this when I posted. It's (a [ i ] ) in the actual game code, so that's not the problem. Download the file if you want to test yourself. If I changed i +=-1 to i -=1 then to be consistent I'd have to re-upload the the project file too, not worth it at this stage, this won't affect how it runs at all, and that is my problem.
 
Last edited:

samspade

Member
I down loaded the project and have a couple notes.

First, your code is annoying to read. This is one reason why you should practice proper code etiquette. At least put spaces where there should be spaces and personally I'd recommend parenthesis and semi colons as well. Second, if you're going to give someone a project, at least remove code until you have the bare minimum of code necessary to create the error. Third, I'm going to assume you didn't run the debugger.

So this is all the code that was needed to reproduce the error:

Code:
/// @description Create Event

var a = layer_get_all();
var i = array_length_1d(a) - 1;

tilemap_layers = 0;

while (i >0)
        {
      
        if layer_get_element_type(a[i]) == layerelementtype_tilemap
            {

            tilemap_id_list[tilemap_layers] = layer_tilemap_get_id(i);
            tilemap_layers += 1
          
            }
          
        i += -1;
      
        }

/// @description Showing the info

draw_text(0,20,"tmap id list " + string(tilemap_id_list));
Running it with the debug shows the problem clearly. tilemap_id_list is not defined once you add four of the objects with sprites (which is what the error said as well). Using a break point on tilemap_id_list in the create event showed that it was never run once you add four objects with sprites and therefore never set.

Understanding why was not immediately obvious, but after reading through the manual and testing a few things it was pretty straightforward. First, this was the code I added to test:

Code:
///added immediately after the code in the create event
var b;
for (var i = 0; i < array_length_1d(a); i += 1) {
    b[i] = layer_get_all_elements(a[i]);
}
Then I stepped through everything with the debugger. Here is the problem. layer ids start at 0. layer elements start at 0. layer elements and layer ids are not the same, but your code uses them interchangeable. The fact that your original code worked at all was a fluke which relied on the fact that you had exactly one element per layer and thus they matched up perfectly. As soon as you started adding elements to layers, you got the wrong result.

I think a solution would be the following:

Code:
var a = layer_get_all();
var i = array_length_1d(a) - 1;

tilemap_layers=0

while (i > 0)
        {
        var element_ids = layer_get_all_elements(a[i])
        if layer_get_element_type(element_ids[0]) == layerelementtype_tilemap
            {

            tilemap_id_list[tilemap_layers] = layer_tilemap_get_id(i);
            tilemap_layers += 1;
          
            }
          
        i += -1;
      
        }
I tested it with your original code and did not get an error, although all of the numbers are incorrect because I didn't bother to change i in the other places it occurred.

I'm not positive this process will always work. It depends upon there only ever being one element on a tile layer, which I believe will always be true. But there is probably a more elegant solution.
 
So this is all the code that was needed to reproduce the error:

Code:
/// @description Create Event

var a = layer_get_all();
var i = array_length_1d(a) - 1;

tilemap_layers = 0;

while (i >0)
        {
 
        if layer_get_element_type(a[i]) == layerelementtype_tilemap
            {

            tilemap_id_list[tilemap_layers] = layer_tilemap_get_id(i);
            tilemap_layers += 1
 
            }
 
        i += -1;
 
        }

/// @description Showing the info

draw_text(0,20,"tmap id list " + string(tilemap_id_list));
Running it with the debug shows the problem clearly. tilemap_id_list is not defined once you add four of the objects with sprites (which is what the error said as well). Using a break point on tilemap_id_list in the create event showed that it was never run once you add four objects with sprites and therefore never set.

Understanding why was not immediately obvious, but after reading through the manual and testing a few things it was pretty straightforward. First, this was the code I added to test:

Code:
///added immediately after the code in the create event
var b;
for (var i = 0; i < array_length_1d(a); i += 1) {
    b[i] = layer_get_all_elements(a[i]);
}
Then I stepped through everything with the debugger. Here is the problem. layer ids start at 0. layer elements start at 0. layer elements and layer ids are not the same, but your code uses them interchangeable. The fact that your original code worked at all was a fluke which relied on the fact that you had exactly one element per layer and thus they matched up perfectly. As soon as you started adding elements to layers, you got the wrong result.

I think a solution would be the following:

Code:
var a = layer_get_all();
var i = array_length_1d(a) - 1;

tilemap_layers=0

while (i > 0)
        {
        var element_ids = layer_get_all_elements(a[i])
        if layer_get_element_type(element_ids[0]) == layerelementtype_tilemap
            {

            tilemap_id_list[tilemap_layers] = layer_tilemap_get_id(i);
            tilemap_layers += 1;
 
            }
 
        i += -1;
 
        }
I tested it with your original code and did not get an error, although all of the numbers are incorrect because I didn't bother to change i in the other places it occurred.

I'm not positive this process will always work. It depends upon there only ever being one element on a tile layer, which I believe will always be true. But there is probably a more elegant solution.
Ok. That did fix the id error. The other numbers relating to tile width, height, and tilemap position are incorrect now like you say, but why is this if I put it inside the now correct if statement
"if layer_get_element_type(element_ids[0]) == layerelementtype_tilemap"?
I need these values to work too which is why they were included. This below seems to get the correct values, is this the right solution inside the if statement after finding the id?

if layer_get_element_type(element_ids[0]) == layerelementtype_tilemap
{
tilemap_id_list[tilemap_layers] = layer_tilemap_get_id(i);

tilemap_x_list[tilemap_layers]=tilemap_get_x(tilemap_id_list[tilemap_layers])
tilemap_y_list[tilemap_layers]=tilemap_get_y(tilemap_id_list[tilemap_layers])

tilemap_tile_w_list[tilemap_layers]=tilemap_get_tile_width(tilemap_id_list[tilemap_layers])
tilemap_tile_h_list[tilemap_layers]=tilemap_get_tile_height(tilemap_id_list[tilemap_layers])

tilemap_layers += 1;
}​
 
Last edited:

samspade

Member
Most of your code in that section uses the local variable i, which 'is' a layer id, when what it needs is the element id. It was a lot of code and I didn't look through it, but if you substituted i for element_ids[0] (or did var ii = element_ids[0] and then substituted all the i's in that section with ii) it would work. Again, the key thing to look for in the code is which functions use an element id and which functions use a layer id. The manual lists it, but its subtle enough that if you aren't thinking about it, you won't notice it (I didn't at first either).

Also, as a note, my solution depends upon a tile layer only ever having one element on it - the tilemap element. If this is not the case, then you'll have to find a new solution, but the idea will still be the same. Find the element id, not the layer id.
 
Also, as a note, my solution depends upon a tile layer only ever having one element on it - the tilemap element. If this is not the case, then you'll have to find a new solution, but the idea will still be the same. Find the element id, not the layer id.
Can 1 tile layer have more than 1 tilemap?
 
Top