gdscriptgodot4

TileSetAtlasSource create_tile function works once and then throws errors


Godot Engine v4.0.2.stable.official.7a0977ce2

I'm loading TileSet atlas texture through the code. Now I need to actually define tiles to use them later. My problem is that the create_tile function works only once, i.e. creates 1 tile, and then throws errors: "Cannot create tile. The tile is outside the texture or tiles are already present in the space the tile would cover".

I thought the problem may be in the texture itself, maybe it loaded incorrectly. I checked by putting it into TextureRect, it appeared normally. I have 256x256 (whole image size) atlas of 16x16 tiles. I iterate the atlas coordinates calling the create_tile function. Here's the code:

func _setup_tile_atlas(atlas: TileSetAtlasSource, tile_size: Vector2i) -> void:
    atlas.texture_region_size = tile_size  # Vector2(16, 16)
    atlas.use_texture_padding = true
    var atlas_size = atlas.get_atlas_grid_size()  # Vector2(16, 16)
    for y in atlas_size.y:
        for x in atlas_size.x:
            var coord = Vector2i(x * tile_size.x, y * tile_size.y)
            atlas.create_tile(coord, tile_size) #ERRORS
            print(atlas.has_tile(coord))
            print(atlas.get_tile_size_in_atlas(coord))
            print(atlas.get_tile_texture_region(coord))

print's are for debugging.

So it says that the only tile that exists is at Vector2i(0, 0). Does it somehow creates a tile with the size of the whole atlas (256x256)? Because atlas.get_tile_texture_region(coord) on the first tile returns [P: (0, 0), S: (256, 256)]. I guess P is for position and S stands for size. Then why, if I give it a tile size argument explicitly?


Solution

  • TLDR: Do this instead, because you are using size and coordinates wrong:

    for y in atlas_size.y:
        for x in atlas_size.x:
            var coord = Vector2i(x, y)
            atlas.create_tile(coord)
    

    Description: The problem is your understanding of the atlas coordinates. These do not represent the pixel position but the position in the grid. Similarly, the size parameter is not the pixel size, but the number of spaces to be occupied in the grid.

    In your case: For a 256x256 pixel image, you specify a region size of 16x16 pixels. This results in 16x16 places in the atlas grid. create_tile(Vector2(0,0), Vector2(16,16)) thus creates a part at position 0,0 in the grid that fills all 16x16 fields (each of which is 16x16 pixels in size, so it is as large as your entire image) The next call (16,16) should already be out of reach of the grid.

    So to simply get 16x16 tiles of your image you would only have to call create_tile(Vector2(x,y)) in your loop to get 16x16 parts of your image as tile. The size parameter would only be relevant if you had individual tiles that are e.g. twice as high, i.e. occupy 2 fields in the grid.

    I hope it is somewhat understandable, as I am having a little difficulty with the explanation and the translation into English. ^^