简体   繁体   English

洪水填充算法无限循环

[英]Flood fill algorithm looping ad infinitum

I'm trying to implement a simple flood fill algorithm to my game in order to find the size of a cavern in a procedurally generated cave; 我正在尝试为我的游戏实现一个简单的洪水填充算法,以便在程序生成的洞穴中找到洞穴的大小; however, I appear to be missing some fundamental point and as such the algorithm I'm using continuously queues even checked points. 然而,我似乎缺少一些基本点,因此我使用的算法连续排队甚至检查点。 My code is as follows: 我的代码如下:

List<Point> sector = new List<Point>();
List<Point> checkd = new List<Point>();
List<Point> queue = new List<Point>();

queue.Add(new Point(startX, startY));

while (queue.Count > 0) {
    Point origin = queue[0];
    queue.RemoveAt(0);
    sector.Add(origin);
    checkd.Add(origin);

    for (int offsetX = -1; offsetX < 2; offsetX++) {
        for (int offsetY = -1; offsetY < 2; offsetY++) {
            if (offsetX == 0 && offsetY == 0 || offsetX == offsetY ||
                offsetX == -offsetY || -offsetX == offsetY)
                continue;

            Point target = new Point(offsetX, offsetY);

            if (target.X < 0 || target.Y < 0 ||
                target.X >= cells.Width || target.Y >= cells.Height ||
                !checkd.Contains (target))
                queue.Add(target);
        }
    }
}

There are many things wrong here. 这里有很多不妥之处。 I tried to preserve your original code as much as possible. 我尽可能地保留原始代码。

  1. Target point calculation: Point target = new Point (offsetX, offsetY); 目标点计算: Point target = new Point (offsetX, offsetY); does not compute the position. 不计算位置。 You probably want to use Point target = new Point(origin.X + offsetX, origin.Y + offsetY); 你可能想使用Point target = new Point(origin.X + offsetX, origin.Y + offsetY);
  2. Checking out of bounds coordinates and if the point is already in checkd cannot be done in one if-statement as in if (target.X < 0 || target.Y < 0 || target.X >= cells.Width || target.Y >= cells.Height || !checkd.Contains (target)) since that would also add points to the queue which are outside the cells grid. 检查越界坐标并且如果该点已经处于checkd则无法在一个if语句中完成,如if (target.X < 0 || target.Y < 0 || target.X >= cells.Width || target.Y >= cells.Height || !checkd.Contains (target))因为这也会在队列中添加cells格网格之外的点。
  3. Checking if the point is in the list by reference. 通过引用检查该点是否在列表中。 Using List<Point>.Contains(Point p) only returns true if the reference to the point is already in the list. 如果对点的引用已经在列表中,则使用List<Point>.Contains(Point p)仅返回true。 This is never the case since target is created as with Point target = new Point(...) . 从来没有这种情况,因为目标是使用Point target = new Point(...)
  4. Before adding the target point you may also want to check if that point is not already in the queue. 在添加目标点之前,您可能还想检查该点是否已在队列中。

So here is my version. 所以这是我的版本。 It travels through all points and eventually adds them to checkd. 它遍历所有点并最终将它们添加到checkd。

List<Point> checkd = new List<Point>();
List<Point> queue = new List<Point>();

queue.Add(new Point(startX, startY));

while (queue.Count > 0)
{
    Point origin = queue[0];
    queue.RemoveAt(0);
    sector.Add(origin);
    checkd.Add(origin);

    for (int offsetX = -1; offsetX < 2; offsetX++)
    {
        for (int offsetY = -1; offsetY < 2; offsetY++)
        {
            // do not check origin or diagonal neighbours
            if (offsetX == 0 && offsetY == 0 || offsetX == offsetY || offsetX == -offsetY || -offsetX == offsetY) continue;

            Point target = new Point(origin.X + offsetX, origin.Y + offsetY);

            // skip out of bounds point
            if (target.X < 0 || target.Y < 0 || target.X >= cells.Width || target.Y >= cells.Height) continue;

            if (!Contains(checkd, target) && !Contains(queue, target))
            {
                queue.Add(target);
            }
        }
    }
}

To check for containment I used the method: 为了检查收容,我使用了以下方法:

private bool Contains(List<Point> list, Point point)
{
    return list.Any(p => p.X == point.X && p.Y == point.Y);
} 

Trying to implement a flood-fill algorithm from scratch may be a good exercise. 尝试从头开始实施泛洪填充算法可能是一个很好的练习。 For a serious project you should consider using a graphics library which has this functionality (and probably more you will need) already implemented. 对于一个严肃的项目,你应该考虑使用一个图形库,它已经实现了这个功能(可能你需要的更多)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM