0

edit: It works now, I moved the getting X and Y into a seperate function, and it seemed to have fixed it (I'm not sure exactly what was wrong, sorry)

I've been making a Tile Editor using WPF and C#, and I seem to have come across a rather odd problem.

When I first run the fill algorithm on a blank canvas, it fills up all tiles except one (usually around (2,7)). Depending on where I start, it jumps around slightly in that area.

What really confuses me is if I flood fill that same area, it will fix the missing tile.

I tried the recursive flood fill as well as the one using a Queue. Here's the code for the Recursion one:

private void FloodFill(Tile node, int targetID, int replaceID) {

    if (targetID == replaceID) return;
    if (node.TileID != targetID) return;

    node.TileID = replaceID;
    SetImageAtCoord(node.X, node.Y);

    if (node.Y + 1 != Map.Height) FloodFill(Map.TileInformation[node.X, node.Y + 1], targetID, replaceID);
    if (node.Y - 1 != -1) FloodFill(Map.TileInformation[node.X, node.Y - 1], targetID, replaceID);
    if (node.X - 1 != -1) FloodFill(Map.TileInformation[node.X - 1, node.Y], targetID, replaceID);
    if (node.X + 1 != Map.Width) FloodFill(Map.TileInformation[node.X + 1, node.Y], targetID, replaceID);
}

Now since I also tried a different method and got the same problem, I thought it might be in the SetImageAtCoord():

private void SetImageAtCoord(int x, int y) {
    IEnumerable<Rectangle> rectangles = MapViewer.Children.OfType<Rectangle>();
    Map.TileInformation[x, y].TileID = CurrentTile;
    foreach (Rectangle rect in rectangles) {
        int X = (int)Canvas.GetLeft(rect) / 32;
        int Y = (int)Canvas.GetTop(rect) / 32;

        if (X == x && Y == y) {
            rect.Fill = CurrentImage;
        }
    }
}

My only guess is that it either misses it on the pass (yet somehow make it every other time), or it has something to do with the placement of the rectangle on the Canvas.

edit: Here is the code for selecting what CurrentImage (and CurrentTile are):

private void Sprite_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
        Rectangle curr = (Rectangle)e.OriginalSource;
        CurrentImage = (ImageBrush)curr.Fill;
        int x = (int)Canvas.GetLeft(curr) / 32;
        int y = (int)Canvas.GetTop(curr) / 32;
        CurrentTile = y * Map.SpriteSheet.GetLength(0) + x;
    }

and the code that calls FloodFill

if (CurrentContol == MapEditControl.Fill) {
            Rectangle ClickedRectangle = (Rectangle)e.OriginalSource;
            ClickedRectangle.Fill = CurrentImage;
            int x = (int)Canvas.GetLeft(ClickedRectangle) / 32;
            int y = (int)Canvas.GetTop(ClickedRectangle) / 32;
            int oldTile = Map.TileInformation[x, y].TileID;
            FloodFill(Map.TileInformation[x, y], oldTile, CurrentTile);
        }

Map.TileInformation is actually only really used to store the ID for exporting to JSON, and the actual rectangles aren't bound to that in anyway (probably should have)

  • Check whether all your nodes' `TileID` values were set. That should tell you whether the flood fill worked (separate to any possible display issues) – Blorgbeard Aug 17 '16 at 03:46
  • I've checked on a few different occasions, and it seems like it is. I also did a check to see if the SetImageAtCoord for that tile was hit, and it wasn't. – Tyler Safaric Aug 17 '16 at 03:50
  • Hang on, why is `SetImageAtCoord` doing `Map.TileInformation[x, y].TileID = CurrentTile;` ? Shouldn't `TileID` have been set by `FloodFill`? What's `CurrentTile`? Is it different to `targetId`? – Blorgbeard Aug 17 '16 at 03:53
  • Never noticed I updated it twice, and when I call FloodFill, it passes in CurrentTile. The thing is, when I update the tileID, it doesn't do any colouring based on that, thats done with rect.Fill, ill update the post to include the selection code – Tyler Safaric Aug 17 '16 at 04:03
  • Can you post the code that calls the initial FloodFill? – Blorgbeard Aug 17 '16 at 04:08
  • Is `y * Map.SpriteSheet.GetLength(0) + x` really what you want to set `TileID` to? That seems wrong.. – Blorgbeard Aug 17 '16 at 04:13
  • again, bit of laziness on my part, I stored the TileSheet as a 2d array, so that's the way to access them. It works fine for the normal draw function as well (and every other time FloodFill is called) – Tyler Safaric Aug 17 '16 at 04:16
  • OK. Well, if the `TileID`s are all set correctly, then it must be a display issue anyway. You could put a check in `SetImageAtCoord` that something was actually hit. Put a `bool hit = false;` at the top, `hit = true;` inside the `if (X == x && Y == y)` part, and then after the loop `if (!hit) throw new Exception();` or something (or set a conditional breakpoint). Then you can inspect the state of your program at the time it goes wrong. – Blorgbeard Aug 17 '16 at 04:20
  • Tried that, and it didn't hit it. I also set a counter to check how many times FloodFill was called, and it was 255 (map total is 256) – Tyler Safaric Aug 17 '16 at 04:28
  • Maybe the tile that's not hit already has its TileID set to CurrentTile, but hasn't had its image set. Perhaps check your `TileID`s before starting the flood? – Blorgbeard Aug 17 '16 at 04:32
  • Alright, now I'm really confused. I added a function to check tileIDs, and checked at every possible point that might affect it. When I run it with the breakpoints at the check, it fills all them, but when I don't, it misses again – Tyler Safaric Aug 17 '16 at 14:25

0 Answers0