godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91k stars 21.17k forks source link

TileMap/TileSet: AtlasTile priority cannot be utilized since update_cell_bitmask() won't call atlastile_get_subtile_by_priority() #43427

Open tinglei8 opened 4 years ago

tinglei8 commented 4 years ago

Godot version:

3.2.3 with mono

OS/device including version:

OSX

Issue description:

I was trying to get randomized subtile selection using priority in an AtlasTile working (by scripting, not in editor), whereas the first subtile was always chosen despite there are 3 different subtiles.

I check all my setup and cannot find why. Then I'm reading the source code at tile_map.cpp update_cell_bitmask() around line 1009 (master) here:

    } else if (tile_set->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) {
==>     if (tile_set->autotile_get_bitmask(id, Vector2(p_x, p_y)) == TileSet::BIND_CENTER) {
            Vector2 coord = tile_set->atlastile_get_subtile_by_priority(id, this, Vector2(p_x, p_y));

            E->get().autotile_coord_x = (int)coord.x;
            E->get().autotile_coord_y = (int)coord.y;
        }
    }

where autotile_get_bitmask(id, coord) should take a subtile coord as its second parameter, but the invocation here passed in the map coordinate?

The evaluation won't be true and there are hardly any occasions atlastile_get_subtile_by_priority() can be called. I don't think it makes sense to check bitmask for an AtlasTile because bitmask only has its usage in an AutoTile?

I didn't try to fix it yet due to lack of environment. And apparently the need in my game can be easily worked around by implementing some subtile randomize logic in the game script and pass an autotile_coord to tile_map::set_cell().

Btw, thank you for the great engine! Maybe the best 2d engine I've ever used (only used the 2d part for the time being).

Steps to reproduce: N/A

Minimal reproduction project:

N/A

golddotasksquestions commented 3 years ago

I have the same issue where I can't use Atlas tiles to randomly place tiles via code. Randomly placing tiles is my primary use for Atlas Tiles.

In my case, I have a Single Tile, which serves as placeholder or basic marker, where I want the random tiles to be placed, and then I have an Atlas Tile with n amount of Tiles that are supposed to appear according to their priority setting ("Enable Priority" in the Tilemap is enabled). This is the code:

extends TileMap

func _ready():
    randomize()
    var used_cells = get_used_cells()
    for i in used_cells.size():
        set_cellv (used_cells[i], 1)

The Atlas tile will appear, however every tile will be replaced with the first Atlas tile, Priority is not used. Using update_dirty_quadrants() makes no difference. I even tried update_bitmask_area() and update_bitmask_region() too without much hope, no effect.

In case someone finds this issue looking for a workaround, instead of Atlas tiles I have now made a bunch of Single Tiles and use

extends TileMap

var different_kinds_total = 30

func _ready():
    randomize()
    var used_cells = get_used_cells()
    for i in used_cells.size():
        var random_tile_id = randi()% different_kinds_total +2
        set_cellv(used_cells[i], random_tile_id)

but using single Tiles clutters the Tilemap node quickly if you need more than a few. So it's anything but an ideal solution.