godotengine / godot

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

TileMap.set_cells_terrain_connect() ignores diagonal tiles connections #89844

Open Igorrreha opened 5 months ago

Igorrreha commented 5 months ago

Tested versions

System information

Godot v4.2.1.stable - Windows 10.0.19044 - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1650 (NVIDIA; 31.0.15.4633) - Intel(R) Core(TM) i5-10300H CPU @ 2.50GHz (8 Threads)

Issue description

Terrain sets with mode "match corners and sides" don't connect diagonal tiles as their peering bitmask describes.

Expected pattern: expected pattern

Real pattern: real pattern

Video:

https://github.com/godotengine/godot/assets/23380802/8aea0662-02fb-46f6-9d7f-8763232f601f

Bitmask: bitmask

Steps to reproduce

Open MRP

  1. Open "res://demo.tscn" scene
  2. Go to tilemap window
  3. Open "terrains" panel
  4. Select "ground" terrain
  5. Select "connect mode" tool
  6. Try to draw some tiles on terrain reproduction

Minimal reproduction project (MRP)

diagonal-tiles-bug.zip

Igorrreha commented 5 months ago

Important thing!

I wrote this tool script and found out that TileMap.set_cells_terrain_path() works fine and only the TileMap.set_cells_terrain_connect() method works buggy.

@tool
extends EditorScript

func _run() -> void:
    var tilemap = get_scene() as TileMap
    tilemap.clear()

    _terrain_path(tilemap, [
        Vector2i(0, 0),
        Vector2i(1, 1),
        Vector2i(2, 2),
    ])

    _terrain_connect(tilemap, [
        Vector2i(4, 0),
        Vector2i(5, 1),
        Vector2i(6, 2),
    ])

func _terrain_path(tilemap: TileMap, cells: Array) -> void:
    tilemap.set_cells_terrain_path(0, cells, 0, 0, false)

func _terrain_connect(tilemap: TileMap, cells: Array) -> void:
    tilemap.set_cells_terrain_connect(0, cells, 0, 0, false)

Test result: test result

VIRTUALXN commented 4 months ago

Hello friend, I have also noticed that this function seems to have some issues, but I am not sure if it is the type you described, but it does not work properly

VIRTUALXN commented 4 months ago

image image

VIRTUALXN commented 4 months ago

image image

VIRTUALXN commented 4 months ago

The set_cells.terrain_path I am using is also abnormal.

IrontMesdents commented 2 weeks ago

I'm posting this here since it's been around 4 months and I think I found the issue. I'm no veteran programmer, so I might be wrong, and I'm also unsure about the best practice format, but I think the problem is in "tile_set.cpp" at the "bool TileSet::is_valid_terrain_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit)" function at line 864.

it looks like this inside the script: image

If I understand this correctly, I think the code stops at the first "p_terrain_mode" and ends up looking for peering bits at "if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES)", since it found a match, which means it never checks for the corner peering bits and behaves like a simple "Match Sides".

If I'm correct, the solution would be to add a third exclusive "if" for "TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES". Something that would look like this, but for all types of "tile_shape": image

That way, when corners and sides are selected, it would check for all peering bits and return their values.

I know screenshots are less than ideal, but as I said, I'm new at this and couldn't figure out how to put the code in my comment cleanly, even with the "Code<>" button. I hope it can at least raise the issue.

I'm willing to update the code myself if needed and copy/paste it here in a correct format with enough pointers to make it work.

IrontMesdents commented 2 weeks ago

I also want to say that I do experience this issue too and it makes my procedurally generated maps a nightmare to fix, if at all possible.