godot icon indicating copy to clipboard operation
godot copied to clipboard

TileData has wrong value for flip_h, filp_v and transpose when accessed

Open CubeXGames opened this issue 10 months ago • 1 comments

Tested versions

  • Reproduced in both v4.5.dev5.official [64b09905c] and v4.4.1.stable.mono.official [49a5bc7b6]

System information

Godot v4.5.dev5 - Windows 10 (build 19045) - Multi-window, 2 monitors - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 2060 - Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz (4 threads)

Issue description

When editing a tilemap in the editor, you can set the rotation / flip of a tile. This value is able to be accessed programmatically through both the is_cell_flipped_h, is_cell_flipped_v, and is_cell_transposed functions on the TileMapLayer class, and the flip_h, flip_v, and transpose properties of the TileData class. However, when accessed, the TileMapLayer functions return an accurate result, but the TileData properties always give a value of false.

Steps to reproduce

The attached project contains a small tilemap with four tiles, each one with a different orientation. When running the project, the console outputs what the TileData class and the TileMapLayer class think the flip_h, flip_v, and transpose of each tile is. TileData returns all false values whereas TileMapLayer returns the correct values.

Minimal reproduction project (MRP)

bug.zip

CubeXGames avatar Jun 12 '25 01:06 CubeXGames

Can confirm this, but I think this is a documentation issue, rather than a bug, the method in question returns the raw data from the TileSet directly, and the tile itself in the TileSet is not flipped or transposed

AThousandShips avatar Jun 12 '25 10:06 AThousandShips

There's no bug here indeed, should be better documented. I'll open a PR for the class reference later.


There are 2 separate sets of transform flags (flips+transpose):

  • Per TileSet (alternative) tile, stored in TileData (as flip_h, flip_v, transpose properties). I call them per-tile flags.
  • Per TileMapLayer cell, stored as 3 bits of the alternative tile id set for the given TileMapLayer cell (obtainable with is_cell_flipped_h, is_cell_flipped_v, is_cell_transposed TileMapLayer methods). I call them per-cell flags.

Why are there 2 sets like that? In the initial 4.0 TileMap implementation there were only per-tile flags. So if the user wanted to e.g. rotate a tile they'd need to create a separate alternative tile just for that. This was cumbersome. To simplify things per-cell flags were added later, in 4.2 (#80144). Thus now we have 2 sets of flags (per-tile flags were not deprecated, they should work as before per-cell flags were added).

But note that how per-tile and per-cell flags are being combined is kinda inconsistent/buggy in both v4.5.dev5.official [64b09905c] and v4.4.1.stable.mono.official [49a5bc7b6]. Specifically, depending on the per-tile flags, e.g. rotating a tile "right" within the editor might instead result in visually rotating it "left"[^1], see the example below. However, given I think nobody reported anything about that, it's rather unlikely that anyone actually uses both per-tile and per-cell flags at the same time. 🙃 Anyway, combining per-tile and per-cell flags should be fixed as a part of #107080 which will be included in 4.5.beta1, now per-cell flags are being applied "independently" on top of the per-tile flags, which should make things consistent UX-wise.

Example

An alternative tile with no per-tile flags set, drawn in a row by rotating it "right"/clockwise (leftmost is not rotated, each next is rotated right one more time). The result is correct / the same in both v4.4.1.stable.official [49a5bc7b6] and v4.5.dev.custom_build [03bd8ba9c] (current master): Image

However, after setting per-tile flip_h, the previously drawn row of tiles becomes a rotate-left sequence in v4.4.1.stable.official [49a5bc7b6] instead of the originally drawn rotate-right sequence. Also pressing rotate-right in the editor when drawing tiles visually rotates the tile left. In the current master (after #107080) the original relative per-cell transforms should be preserved no matter how you'll modify per-tile flags later (a rotate-right tile sequence will remain a rotate-right tile sequence etc.).

v4.4.1.stable.official [49a5bc7b6] v4.5.dev.custom_build [03bd8ba9c]
(current master)
Image Image
Image Image

[^1]: Why? Within the TileSet editor there are only per-tile flags applied to the created/shown alternative tiles, meaning this is what the user sees and thus this is what should be treated as the "base tile" to which the per-cell flags are being applied to. Meaning conceptually the per-tile flags need to be applied first, then per-cell flags on top of such transformed tile. These being 2 seperate steps was previously not taken into account when combining flags.


Also for reference here's how the flags are being combined currently: https://github.com/godotengine/godot/blob/03bd8ba9c23d31f8f658f97093fd3f2e4a0f9031/scene/2d/tile_map_layer.cpp#L2647-L2659 (I don't think it needs to be anyhow exposed (with a new method etc.). As mentioned transforming just the per-cell flags should be consistent currently (no matter the per-tile flags) so it should be fine to modify them directly. 🤔)

kleonc avatar Jun 12 '25 16:06 kleonc