如何使用列表与数组向封闭区域填充GameObject?应采用何种填充算法?
封闭网格区域GameObject填充方案
你当前编写的固定方向嵌套循环逻辑仅支持规则矩形边界的填充,无法适配任意形状的封闭轮廓,实现该需求最适配的算法是*洪水填充(Flood Fill)*算法。
算法核心逻辑
从一个确定位于封闭区域内部的种子点出发,按你设定的填充步长(你代码中使用的10单位)向四周相邻网格点扩展,遇到边界点位、已填充过的点位就停止扩展,直到遍历完所有区域内的可用点位。
为避免填充区域过大时递归触发栈溢出,优先使用队列实现的广度优先迭代版,示例代码如下:
// 填充步长,和边界Cube的放置间隔保持一致 public float fillStep = 10f; // XZ平面的4个扩展方向,需要支持对角线填充可新增4个对角方向 private Vector2[] extendDirs = new Vector2[] { new Vector2(1, 0), new Vector2(-1, 0), new Vector2(0, 1), new Vector2(0, -1) }; public void FillClosedArea(Vector3 seedPos) { // 校验种子点合法性:不在边界上、未被填充过 if (IsExists(seedPos)) return; Queue<Vector3> fillQueue = new Queue<Vector3>(); fillQueue.Enqueue(seedPos); // 记录已处理点位,避免重复入队 HashSet<Vector3> processedPoints = new HashSet<Vector3>(); processedPoints.Add(seedPos); while (fillQueue.Count > 0) { Vector3 currentPos = fillQueue.Dequeue(); // 放置填充Cube PutACube(currentPos); // 遍历所有方向扩展 foreach (var dir in extendDirs) { float nextX = currentPos.x + dir.x * fillStep; float nextZ = currentPos.z + dir.y * fillStep; Vector3 nextPos = new Vector3(nextX, currentPos.y, nextZ); // 点位未处理、不在边界上则加入队列 if (!processedPoints.Contains(nextPos) && !IsExists(nextPos)) { processedPoints.Add(nextPos); fillQueue.Enqueue(nextPos); } } } }
使用注意事项
- 种子点必须确保完全位于封闭区域内部,可在用户绘制完封闭轮廓后,取轮廓包围盒的中心点校验通过后作为种子点
IsExists方法需要能准确识别边界点位和已填充点位,避免填充超出轮廓范围- 若需要适配斜向的封闭轮廓,可以在扩展方向数组中增加对角线方向

内容的提问来源于stack exchange,提问作者Muhammet Ali Gözalan
相关产品推荐
相关产品推荐

