None of the Fill methods (FloodFill, BoxFill, SetTilesBlock) work

Hey all, experiencing this issue on the very latest version of unity (2022.2.1f1), but it was also occurring on the latest version of 2021 unity which I upgrade this project from to try and get it working.

As the title says, none of the Tilemap.FloodFill, BoxFill, or SetTilesBlock work for filling in a large portion of the tilemap with the same tile. For all 3 of the code snippets below, I get null in the second Debug:

FloodFill

BoundsInt zone = new BoundsInt(startX, startY, 0, sizeX, sizeY, 0); // startX, startY = 0, sizeX, sizeY = 8. But same issue occurs with any valid parameters
Tilemaps[0].SetTile(zone.min, BackgroundTile);
Tilemaps[0].SetTile(zone.max, BackgroundTile);
Tilemaps[0].FloodFill(zone.min, BackgroundTile);
Debug.Log(Tilemaps[0].GetTile(zone.min)); // Outputs name of the background tile
Debug.Log(Tilemaps[0].GetTile(zone.min + new Vector3Int(1, 1, 1))); // Outputs null

BoxFill

BoundsInt zone = new BoundsInt(startX, startY, 0, sizeX, sizeY, 0); // startX, startY = 0, sizeX, sizeY = 8. But same issue occurs with any valid parameters
Tilemaps[0].SetTile(zone.min, BackgroundTile);
Tilemaps[0].SetTile(zone.max, BackgroundTile);
Tilemaps[0].BoxFill(zone.min, BackgroundTile, 0, 0, sizeX - 1, sizeY - 1);
Debug.Log(Tilemaps[0].GetTile(zone.min)); // Outputs name of the background tile
Debug.Log(Tilemaps[0].GetTile(zone.min + new Vector3Int(1, 1, 1))); // Outputs null

SetTilesBlock

BoundsInt zone = new BoundsInt(startX, startY, 0, sizeX, sizeY, 0); // startX, startY = 0, sizeX, sizeY = 8. But same issue occurs with any valid parameters
TileBase[] background = new TileBase[sizeY * sizeY];
Array.Fill(background, BackgroundTile);
Tilemaps[0].SetTile(zone.min, BackgroundTile);
Tilemaps[0].SetTile(zone.max, BackgroundTile);
Tilemaps[0].SetTilesBlock(zone, background);
Debug.Log(Tilemaps[0].GetTile(zone.min)); // Outputs name of the background tile
Debug.Log(Tilemaps[0].GetTile(zone.min + new Vector3Int(1, 1, 1))); // Outputs null

The only way I can achieve filling in a large part of the map with the same tile is with SetTiles

BoundsInt zone = new BoundsInt(startX, startY, 0, sizeX, sizeY, 0); // startX, startY = 0, sizeX, sizeY = 8. But same issue occurs with any valid parameters
TileBase[] background = new TileBase[sizeY * sizeY];
Array.Fill(background, BackgroundTile);
Vector3Int[] backgroundPositions = new Vector3Int[sizeY * sizeY];
int index = 0;
for (int y = startY; y < startY + sizeY; y++)
{
    for (int x = startX; x < startX + sizeX; x++)
    {
        backgroundPositions[index] = new Vector3Int(x, y, 0);
        index++;
    }
}
Tilemaps[0].SetTile(zone.min, BackgroundTile);
Tilemaps[0].SetTile(zone.max, BackgroundTile);
Tilemaps[0].SetTiles(backgroundPositions, background);
Debug.Log(Tilemaps[0].GetTile(zone.min)); // Outputs name of the background tile
Debug.Log(Tilemaps[0].GetTile(zone.min + new Vector3Int(1, 1, 1))); // Outputs name of background tile

However, this is not ideal due to just the amount of looping, especially when generating large maps (1024*1024) or having to perform this on many smaller tilemap layers. Any ideas what is causing this issue?

This looks like it is just a nullref. Figure out why there’s no tile at that address.

How to fix a NullReferenceException error

https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

Three steps to success:

  • Identify what is null ← any other action taken before this step is WASTED TIME
  • Identify why it is null
  • Fix that
zone.min + new Vector3Int(1, 1, 1)

Shouldn’t this be Vector3Int(1, 1, 0) or Vector3Int(1, 0, 1) instead of Vector3Int(1, 1, 1)? Not sure if it’s xy or xz plane but 1, 1, 1 is most likely wrong.

My bad yea, it should be Vector3Int(1, 1, 0). I included the Debug to only show that none of the Fill methods are doing anything in Editor. The below picture is essentially what I see in the editor after running those snippets, and Vector3Int(1, 1, 0) also shows null.

The issue with null ref is exactly why I posted this question.

What is null:
The spot in the Tilemap that should have a background tileset. The background asset going into the Unity API is not null.

Why is it null:
Unity API doesn’t seem to be filling it in and doing what it is supposed to? If the inputs are not null and are valid, the API shouldn’t be nullifying the output/results.

Fix that:
No idea how / what the cause is. Potentially a bug with the Unity api. Which is the reason for the post.

8733222--1182129--InEditor.PNG

Hi, could you try the following to set up the bounds and check if that helps?

BoundsInt zone = new BoundsInt(startX, startY, 0, sizeX, sizeY, 1);

Sorry for the late reply. This doesn’t seem to work either, still getting the same thing:
8740989--1183773--upload_2023-1-19_11-17-9.png

@QuariYune

Thanks for the update, I think I understand the issue better now!

This will not work for Tilemap.FloodFill or BoxFill, as it will replace Tiles based on the initial position set. This works similarly to Paint in Windows, where if you try to fill a red pixel with a black pixel, it will only change the red pixels at the location to black and so on.

As you have set the target position (zone.min) with the BackgroundTile, when calling Tilemap.FloodFill at zone.min, it will attempt to change the target Tile at that position (BackgroundTile) to the BackgroundTile. It will then check its neighbours to see if they are the original target Tile and then change them. As the neighbours are not the target Tile (null), nothing will happen and the FloodFill algorithm will stop.

Instead of calling SetTile with zone.min and zone.max, you could change the Tilemap’s origin and size with the values first, before calling FloodFill. Using FloodFill with zone.min + Vector3Int.right should work too.

The bounds should work for SetTilesBlock as that requires a depth of at least 1 (size.z).

Looks like the SetTilesBlock indeed works for filling the area with a depth of 1. Though its a bit unfortunate that the floodfill and boxfill don’t treat “null / empty” as a valid target for replacement. While I understand operations on null values can get finicky, I just tested 3 different art programs that all allowed me to bucket fill a newly opened unaltered file (MS Paint, Aseprite, Krita). In any case thanks for the help @ChuanXin