洪水填充算法判断地图是否有封闭区域
我看的一个生成npc地图的教程里,用洪水填充算法来判断所有地形网格没有封闭区域,实际上就是根据所有能访问到的地形网格与所有网格减去障碍物网格的数量作对比,以此来判断是否有封闭区域的。
如何判断网格能否访问到,无非是如果当前网格能访问,它的上下左右不能全是障碍。判断网格时要从出生点向上下左右节点延伸。
实际上如果不指定出生点,那就可以不用洪水填充,直接俩for循环,遍历所有节点,如果上下左右不全是障碍,那就+1,最后和实际需要的网格数量对比即可。
/// <summary>
/// 判断地图是否有封闭区域
/// </summary>
/// <param name="obstacleMap">障碍物的二维数组 [x,y] == true 表示是障碍物</param>
/// <param name="currentObstacleCount">当前障碍物数量</param>
/// <returns></returns>
bool MapIsFullyAccessible(bool[,] obstacleMap, int currentObstacleCount)
{
// 表示当前处理节点是否访问过的二维数组
var mapFlags = new bool[obstacleMap.GetLength(0), obstacleMap.GetLength(1)];
var queue = new Queue<Coord>();
queue.Enqueue(currentMap.mapCentre);
mapFlags[currentMap.mapCentre.X, currentMap.mapCentre.Y] = true;
// 当前可访问的节点数量
var accessibleTileCount = 1;
while (queue.Count > 0)
{
var tile = queue.Dequeue();
for (var x = -1; x <= 1; x++)
{
for (var y = -1; y <= 1; y++)
{
// 判断是否是当前节点的上下左右节点
if (x != 0 && y != 0) continue;
var neighborX = tile.X + x;
var neighborY = tile.Y + y;
// 不能越界
if (neighborX < 0 || neighborX >= obstacleMap.GetLength(0) || neighborY < 0 ||
neighborY >= obstacleMap.GetLength(1)) continue;
if (mapFlags[neighborX, neighborY] || obstacleMap[neighborX, neighborY]) continue;
mapFlags[neighborX, neighborY] = true;
queue.Enqueue(new Coord(neighborX, neighborY));
accessibleTileCount++;
}
}
}
// 期望能访问到的节点数量:所有节点与障碍物节点数量相减
var targetAccessibleTileCount = currentMap.mapSize.X * currentMap.mapSize.Y - currentObstacleCount;
return targetAccessibleTileCount == accessibleTileCount;
}