河流生成算法中瓦片相邻区域比较代码的优化方案问询
优化河流生成算法的相邻瓦片检查逻辑
嘿,我完全懂你现在的烦恼——重复写一堆几乎一模一样的if语句不仅代码臃肿到难以维护,后续要扩展更远的相邻瓦片检查时,代码量会爆炸式增长,还会拖慢运行效率。咱们来重构这段逻辑,让它更简洁、高效,还能轻松扩展。
核心问题分析
你的原代码里,8次重复的if本质上只是遍历当前瓦片的8个相邻方向,每次做的操作都是:计算相邻坐标→获取降雨值→判断条件→设置瓦片。这种重复劳动完全可以用「方向数组+循环」来替代。
第一步:用方向数组消除代码冗余
首先,我们把8个相邻方向的偏移量(列偏移dx,行偏移dy)整理成一个数组,这样只需要一次循环就能遍历所有相邻位置:
// 定义8个相邻方向的偏移量(覆盖上下左右+四个对角线) let neighborOffsets: [(Int, Int)] = [ (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (1, 0), (1, 1), (0, 1) ]
第二步:重构核心逻辑
接下来把原有的重复逻辑改成循环遍历,同时还能顺便实现你提到的「找出最低值」的需求:
// 先获取当前瓦片的降雨值,避免重复调用方法 let currentRain = Rain.value(atPosition: vector_float2(Float(columns), Float(rows))) if currentRain == 1.0 { var shouldSetRiverTile = false var minNeighborRain = Float.greatestFiniteMagnitude var minRainPosition: (col: Int, row: Int)? // 记录降雨最低的相邻瓦片位置 // 遍历所有相邻方向 for (dx, dy) in neighborOffsets { let neighborCol = columns + dx let neighborRow = rows + dy // 👉 这里一定要加边界检查!避免访问超出地图范围的无效瓦片 guard neighborCol >= 0, neighborCol < mapWidth, neighborRow >= 0, neighborRow < mapHeight else { continue } let neighborRain = Rain.value(atPosition: vector_float2(Float(neighborCol), Float(neighborRow))) // 检查是否满足降雨条件 if neighborRain == 0.9 { shouldSetRiverTile = true } // 追踪降雨值最低的相邻瓦片 if neighborRain < minNeighborRain { minNeighborRain = neighborRain minRainPosition = (neighborCol, neighborRow) } } // 只要有一个相邻瓦片满足条件,就设置当前瓦片为河流 if shouldSetRiverTile { fullMap.setTileGroup(tileDef4, forColumn: columns, row: rows) } // 👉 如果后续需要根据最低值瓦片做更多逻辑(比如河流流向),可以用minRainPosition // 比如:if let minPos = minRainPosition, minNeighborRain < 0.8 { ... } }
第三步:性能升级——缓存降雨值
如果Rain.value(atPosition:)是一个比较耗时的操作(比如从纹理读取、实时计算Perlin噪声),提前缓存整个降雨地图到二维数组能大幅提升效率,避免重复的方法调用和坐标转换:
// 提前初始化并缓存整个降雨地图(假设你知道地图的宽mapWidth、高mapHeight) var rainCache: [[Float]] = Array(repeating: Array(repeating: 0.0, count: mapHeight), count: mapWidth) for col in 0..<mapWidth { for row in 0..<mapHeight { rainCache[col][row] = Rain.value(atPosition: vector_float2(Float(col), Float(row))) } }
之后访问降雨值时,直接用数组索引即可,速度快很多:
// 替换原来的Rain.value调用 let neighborRain = rainCache[neighborCol][neighborRow]
扩展建议
如果后续需要检查更远的相邻瓦片(比如2格、3格外),只需要在外层加一个控制距离的循环,生成对应范围的偏移量即可,比如检查距离为n的所有瓦片:
let maxDistance = 2 // 检查2格范围内的所有瓦片 for dx in -maxDistance...maxDistance { for dy in -maxDistance...maxDistance { guard dx != 0 || dy != 0 else { continue } // 跳过当前瓦片本身 let neighborCol = columns + dx let neighborRow = rows + dy // 后续逻辑同上... } }
这样不管你要检查多少范围的瓦片,代码量都不会爆炸,逻辑也清晰很多。
内容的提问来源于stack exchange,提问作者E. Huckabee
相关产品推荐
相关产品推荐

