Unity网格索引越界问题排查及负索引网格实现咨询
Unity网格索引越界问题排查及负索引网格实现
一、当前错误原因
从你给出的Debug信息和代码来看,触发index was outside the bounds of the array错误的原因很明确:
- 负索引直接访问数组:你的
Grid底层用的是C#标准二维数组CellType[,] _grid,这类数组只支持非负索引(范围是0 <= i < Width、0 <= j < Height)。而你当前访问的坐标是(-1,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
相关产品推荐
相关产品推荐

