从 Grid 中检索节点时发生 IndexOutOfRange

IndexOutOfRange occuring when retrieving nodes from Grid

我正在实施呼吸优先搜索并尝试获取邻居节点,但是在从网格(网格为 100x100)获取邻居节点时我 运行 遇到 IndexOutOfRange 错误。我理解这个错误,但我不明白它为何以及如何超出网格范围。当 运行ning Dijkstra 路径查找时,这种查找邻居的实现非常有效,但是当我 运行 BFS 时,它似乎给了我一个 IndexOutOfRange.

我已经尝试检查当前节点的 x、z 位置以确保其在边界内,然后在网格中执行查找邻居,但这似乎对我也不起作用,产生了同样的错误。希望能深入了解我可能会在哪里出错。

网格classGrid.cs

BFS BFS.cs

邻居功能

public List<Node> GetNeighbours(Node currentNode)
{        
    var x = Convert.ToInt32(currentNode.Position.x);
    var z = Convert.ToInt32(currentNode.Position.z);

    var neighbours = new List<Node>() // Unity mentions error occurring here
    {
        grid[x - 1, z],
        grid[x + 1, z], 
        grid[x, z - 1],
        grid[x, z + 1],
        grid[x + 1, z + 1],
        grid[x - 1, z + 1],
        grid[x - 1, z - 1],
        grid[x + 1, z - 1]
    };

    var walkableNeighbours = new List<Node>();

    foreach (var neighbour in neighbours)
    {
        if (!IsCellOccupied(neighbour) && IsInLevelBounds(neighbour))
            walkableNeighbours.Add(neighbour);
    }

    return walkableNeighbours;
}

我试过在获取网格邻居之前检查边界,但这也不起作用,奇怪地给我同样的错误。

private bool IsIndexInBounds(int x, int z)
{
    if (x > 0 && x <= Width - 1 && z > 0 && z <= Height - 1)
        return true;

    return false;
}

public List<Node> GetNeighbours(Node currentNode)
{        
    var x = Convert.ToInt32(currentNode.Position.x);
    var z = Convert.ToInt32(currentNode.Position.z);

    if(IsIndexInBounds(x,z) { ... }
    
        var neighbours = new List<Node>()
        {
            grid[x - 1, z],
            grid[x + 1, z], 
            grid[x, z - 1],
            grid[x, z + 1],
            grid[x + 1, z + 1],
            grid[x - 1, z + 1],
            grid[x - 1, z - 1],
            grid[x + 1, z - 1]
        };
   //...
}

建议

动态查找当前点周围的邻居

List<Node> neighbours = new List<Node>();
for (int w = Mathf.Max(0, x - 1); w <= Mathf.Min(x + 1, Width); w++)
{
    for (int h = Mathf.Max(0, z - 1); h <= Mathf.Min(z + 1, Height); z++)
    {
        if (w != x || h != z)
        {
            neighbours.Add(grid[w, h]);
        }
    }
}

我相信你面临的问题是你没有考虑边缘情况,例如当你处于 x 极限时,就不会有 x+1 的可能性,所以你的组合应该只是:

var neighbours = new List<Node>()
    {
        grid[x - 1, z],
        grid[x, z - 1],
        grid[x, z + 1],
        grid[x - 1, z + 1],
        grid[x - 1, z - 1],
    };

或者如果你在角落里,那么唯一可能的邻居是 [x - 1, z],grid[x, z - 1],grid[x - 1, z - 1]。您当前的节点创建始终试图找到该点周围的 8 个邻居,但您必须记住,情况并非总是如此。

您可以找到动态查找此问题的算法 here 或者您可以根据自己的情况尝试添加边缘情况组合,如果您愿意的话。

x - 1 .. z - 1 .. x + 1 .. z + 1 .. 没有检查这些是否真的可能

您只查看您当前的位置

if(IsIndexInBounds(x, z) { ... }

但是您需要检查每个邻居是否存在,例如蛮力方式

var neighbours = new List<Node>();

var higherX = x + 1;
var lowerX = x - 1;
var higherZ = z + 1;
var lowerZ = z - 1;

if(IsIndexInBounds(lowerX,  z)       neighbours.Add(grid[lowerX,  z]);
if(IsIndexInBounds(higherX, z)       neighbours.Add(grid[higherX, z]);
if(IsIndexInBounds(x,       lowerZ)  neighbours.Add(grid[x,       lowerZ]);
if(IsIndexInBounds(x,       higherZ) neighbours.Add(grid[x,       higherZ]);
if(IsIndexInBounds(higherX, higherZ) neighbours.Add(grid[higherX, higherZ]);
if(IsIndexInBounds(lowerX,  higherZ) neighbours.Add(grid[lowerX,  higherZ]);
if(IsIndexInBounds(lowerX,  lowerZ)  neighbours.Add(grid[lowerX,  lowerZ]);
if(IsIndexInBounds(higherX, lowerZ)  neighbours.Add(grid[higherX, lowerZ]);

您的 IsIndexInBounds 并不完全正确,顺便说一句,c# 中的索引以 0 开头,因此您实际上需要 >= 0 而不是 > 0。你也可以简单地做到

private bool IsIndexInBounds(int x, int z)
{
    return x >= 0 && x < Width && z >= 0 && z < Height;
}