如何高效查找二维数组中Tile类单元格的相邻单元格?
嘿,这个问题我之前做格子类游戏的时候也纠结过!四层嵌套循环确实看着头大,而且先全量创建Tile再遍历一遍加邻居,确实有点冗余。咱们来聊聊几个更清爽还能优化效率的实现方式:
1. 用预定义偏移量数组替代嵌套循环
把8个方向的偏移提前存成一个数组,这样就能把原来的四层循环简化成三层,代码可读性直接拉满,逻辑也更清晰。核心思路就是把“遍历x/y偏移”改成“遍历预定义的方向集合”,本质和你找到的那篇帖子思路一致,只是更贴合你的场景。
示例代码(C#):
// 先把8个相邻方向的偏移都列出来,看着也直观 var neighborOffsets = new (int dx, int dy)[] { (-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1) }; int playfieldWidth = ...; int playfieldHeight = ...; Tile[,] playfieldTiles = new Tile[playfieldWidth, playfieldHeight]; // 第一步:创建所有Tile for (int y = 0; y < playfieldHeight; y++) { for (int x = 0; x < playfieldWidth; x++) { playfieldTiles[x, y] = new Tile(); } } // 第二步:给每个Tile添加邻居 for (int y = 0; y < playfieldHeight; y++) { for (int x = 0; x < playfieldWidth; x++) { var currentTile = playfieldTiles[x, y]; foreach (var (dx, dy) in neighborOffsets) { int neighborX = x + dx; int neighborY = y + dy; // 检查是否在地图边界内 if (neighborX >= 0 && neighborX < playfieldWidth && neighborY >= 0 && neighborY < playfieldHeight) { currentTile.dnTiles.Add(playfieldTiles[neighborX, neighborY]); } } } }
这种方式虽然还是要遍历两次数组,但代码结构清晰太多,后续维护起来也方便,而且对于大多数游戏场景来说,性能差异完全可以忽略。
2. 边创建Tile边处理邻居(更高效)
如果想减少一次全量遍历,可以在创建每个Tile的时候,直接去关联已经创建好的相邻Tile。因为我们是按行优先顺序创建的,所以当前Tile的左上、上、右上、左这几个方向的Tile肯定已经存在了,只需要处理这些方向,然后互相添加邻居就行——这样每个邻居对只会被处理一次,还省了后续的全量遍历。
示例代码:
int playfieldWidth = ...; int playfieldHeight = ...; Tile[,] playfieldTiles = new Tile[playfieldWidth, playfieldHeight]; // 只需要处理已经创建过的邻居方向 var preCreatedOffsets = new (int dx, int dy)[] { (-1, -1), (-1, 0), (-1, 1), (0, -1) }; for (int y = 0; y < playfieldHeight; y++) { for (int x = 0; x < playfieldWidth; x++) { var currentTile = new Tile(); playfieldTiles[x, y] = currentTile; foreach (var (dx, dy) in preCreatedOffsets) { int neighborX = x + dx; int neighborY = y + dy; if (neighborX >= 0 && neighborX < playfieldWidth && neighborY >= 0 && neighborY < playfieldHeight) { var neighborTile = playfieldTiles[neighborX, neighborY]; // 互相添加邻居,一次操作搞定双向关联 currentTile.dnTiles.Add(neighborTile); neighborTile.dnTiles.Add(currentTile); } } } }
这种方式只需要遍历一次数组,而且邻居的添加操作直接减半(不用每个Tile都遍历8个方向),对于大尺寸的游戏场来说,性能提升会很明显。
额外小技巧:延迟加载邻居(极端场景)
如果你的游戏场特别大,或者大部分Tile的邻居很少被用到,还可以考虑延迟加载——也就是等到需要访问某个Tile的邻居时,再实时计算并缓存结果。不过这种方式适合特殊场景,一般游戏里提前初始化邻居会更稳定,避免运行时的计算开销。
内容的提问来源于stack exchange,提问作者Sander Koldenhof
相关产品推荐
相关产品推荐

