You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity网格索引越界问题排查及负索引网格实现咨询

Unity网格索引越界问题排查及负索引网格实现

一、当前错误原因

从你给出的Debug信息和代码来看,触发index was outside the bounds of the array错误的原因很明确:

  1. 负索引直接访问数组:你的Grid底层用的是C#标准二维数组CellType[,] _grid,这类数组只支持非负索引(范围是0 <= i < Width、0 <= j < Height)。而你当前访问的坐标是(-1,2),直接用负索引操作数组必然触发越界。
  2. 网格数据不同步:AddToGrid方法直接往_houseStructure这类列表中添加坐标,但完全没有同步更新_grid二维数组,导致网格的实际存储数据和列表完全脱节,后续基于数组的访问逻辑肯定出问题。

二、先解决当前越界错误

1. 给网格访问加边界检查

修改GetWakableAdjacentCells,访问数组前先判断坐标是否合法,非法坐标直接判定为不可行走:

public List<Point> GetWakableAdjacentCells(int x, int y, bool isAgent)
{
    List<Point> adjacentCells = GetAllAdjacentCells(x, y);
    
    for (int i = adjacentCells.Count - 1; i >= 0; i--)
    {
        Point cell = adjacentCells[i];
        // 先检查坐标是否在网格合法范围内
        if (cell.X < 0 || cell.X >= Width || cell.Y < 0 || cell.Y >= Height)
        {
            adjacentCells.RemoveAt(i);
            continue;
        }
        if (!IsCellWakable(_grid[cell.X, cell.Y], isAgent))
        {
            adjacentCells.RemoveAt(i);
        }
    }
    return adjacentCells;
}

2. 修复AddToGrid,同步网格数据

不要直接操作列表,改用Grid的索引器来设置单元格类型,这样既能自动维护列表,还能提前过滤非法坐标:

public Grid AddToGrid(Vector3Int position, string type)
{
    int x = position.x;
    int z = position.z;
    // 先判断坐标是否合法,再执行设置
    if (x >= 0 && x < placementGrid.Width && z >= 0 && z < placementGrid.Height)
    {
        switch (type)
        {
            case "Structure":
                placementGrid[x, z] = CellType.Structure;
                break;
            case "SpecialStructure":
                placementGrid[x, z] = CellType.SpecialStructure;
                break;
            case "Road":
                placementGrid[x, z] = CellType.Road;
                break;
        }
    }
    return placementGrid;
}

三、实现支持负索引的网格

要支持负索引,核心是做坐标偏移——把用户传入的正负坐标映射成数组能接受的非负索引。修改后的Grid类示例:

public class Grid
{
    public CellType[,] _grid;
    private int _width;
    public int Width => _width;
    private int _height;
    public int Height => _height;
    
    // 偏移量:用来把负坐标转成数组的非负索引
    private int _offsetX;
    private int _offsetY;
    // 对外暴露的坐标范围,方便判断合法性
    public int MinX => -_offsetX;
    public int MaxX => _width - _offsetX - 1;
    public int MinY => -_offsetY;
    public int MaxY => _height - _offsetY - 1;

    public List<Point> _roadList = new List<Point>();
    public List<Point> _specialStructure = new List<Point>();
    public List<Point> _houseStructure = new List<Point>();

    // 构造函数:传入网格实际宽高,以及x、y轴的偏移量(即支持的负坐标最大绝对值)
    public Grid(int width, int height, int offsetX, int offsetY)
    {
        _width = width;
        _height = height;
        _offsetX = offsetX;
        _offsetY = offsetY;
        _grid = new CellType[width, height];
    }

    // 重写索引器,自动处理坐标偏移
    public CellType this[int x, int y]
    {
        get
        {
            if (x < MinX || x > MaxX || y < MinY || y > MaxY)
            {
                throw new IndexOutOfRangeException($"坐标({x},{y})超出网格范围");
            }
            // 转换为数组的非负索引
            int arrayX = x + _offsetX;
            int arrayY = y + _offsetY;
            return _grid[arrayX, arrayY];
        }
        set
        {
            if (x < MinX || x > MaxX || y < MinY || y > MaxY)
            {
                throw new IndexOutOfRangeException($"坐标({x},{y})超出网格范围");
            }
            int arrayX = x + _offsetX;
            int arrayY = y + _offsetY;
            
            // 先移除旧类型对应的列表项(如果需要维护列表的准确性)
            var point = new Point(x, y);
            switch (_grid[arrayX, arrayY])
            {
                case CellType.Road:
                    _roadList.Remove(point);
                    break;
                case CellType.SpecialStructure:
                    _specialStructure.Remove(point);
                    break;
                case CellType.Structure:
                    _houseStructure.Remove(point);
                    break;
            }
            
            // 添加新类型对应的列表项
            if (value == CellType.Road)
            {
                _roadList.Add(point);
            }
            else if (value == CellType.SpecialStructure)
            {
                _specialStructure.Add(point);
            }
            else if (value == CellType.Structure)
            {
                _houseStructure.Add(point);
            }
            
            _grid[arrayX, arrayY] = value;
        }
    }
}

使用示例

比如要支持x从-2到3(共6个单位),y从-1到2(共4个单位),可以这样创建网格:

// offsetX=2:x=-2时转成数组索引0,x=3时转成5(对应宽度6)
// offsetY=1:y=-1时转成数组索引0,y=2时转成3(对应高度4)
Grid grid = new Grid(6, 4, 2, 1);
// 现在可以直接用负索引访问
grid[-1, 1] = CellType.Road;

内容的提问来源于stack exchange,提问作者VChuckShunA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 08:15:27