【发布时间】:2020-03-19 13:14:23
【问题描述】:
我在另一个脚本中多次运行“GenerateFloodFillData”。它基于 int 变量 X 在 for 循环中循环该函数。如果我只运行一次函数(floodFillSampleRate = 1),那么它似乎每次都会响应。如果我 floodFillSampleRate = 10,则 Unity 编辑器在几次尝试中停止响应 25%。当 floodFillSampleRate = 100 时,它会计算一段时间,然后停止响应,并且进程永远不会“返回”到响应状态。我知道为什么该函数需要很长时间来计算,并且它还使用了一个 while 循环(并不总是推荐)。但这不应该是无限循环/递归问题,因为该函数之前已经执行过。
我知道在我的地形上更改了 meshChunkSize(给 Vector3[] allVertices 方式较低的元素)修复了进程中的无限“无响应”。因此,对于大约 2100 个顶点,它总是在 floodfillSampleRate 上以任意数字贯穿。当我达到大约 15-20k 个顶点时,它仍然可以工作,但统一停止响应几秒钟,然后它会返回响应并输出结果。如果我在 FloodFillSampleRate 上达到我的默认块大小,即 59k 顶点,那么它只是处于“无响应”模式,对于我来说是无限的(我已经等待了大约 25-30 分钟的过程返回但是我没有)。
这是否是一些时间复杂性问题,只是使得循环数次所需时间的更多顶点太长或其他什么?我不知道确切的时间复杂度,但我会假设它至少是线性的,因为添加更多的顶点意味着更多的顶点在 while 循环中排队和循环。我似乎也没有代码中的无限循环。我尝试用 try-catch 构建整个函数(我不确定我是否这样做正确)并且我没有收到任何错误,它只是冻结了,所以如果统一进程没有响应,我怎么能得到错误。
private static Queue<Vector3> q = new Queue<Vector3>();
private static List<Vector3> l = new List<Vector3>();
private static void CheckIfQueueNeighbor(int index, float limit, Vector3[] allVertices, Vector3 currentNode)
{
if (allVertices[index].y - currentNode.y <= limit)
{
if (l.Contains(allVertices[index]) == false)
{
l.Add(allVertices[index]);
q.Enqueue(allVertices[index]);
}
else
{
// Do nothing if already in list
}
}
}
public static float GenerateFloodFillData(float heightThresholdValue, MeshFilter meshFilter)
{
Vector3[] verts = meshFilter.sharedMesh.vertices;
Vector3 cNode;
//Initialize
int width = (int)meshFilter.sharedMesh.bounds.size.x;
q = new Queue<Vector3>();
l = new List<Vector3>();
//Start at index 0, maybe be any corner or vertex in mesh. Investigate more.
q.Enqueue(verts[0]);
while (q.Count > 0)
{
cNode = q.Dequeue();
//Add traversable nodes: Left, right, top & bottom
if ((Array.IndexOf(verts, cNode) - 1) >= 0)
{
CheckIfQueueNeighbor(Array.IndexOf(verts, cNode) - 1, heightThresholdValue, verts, cNode);
}
if ((Array.IndexOf(verts, cNode) + 1) < verts.Length)
{
CheckIfQueueNeighbor(Array.IndexOf(verts, cNode) + 1, heightThresholdValue, verts, cNode);
}
if ((Array.IndexOf(verts, cNode) - width) >= 0)
{
CheckIfQueueNeighbor(Array.IndexOf(verts, cNode) - width, heightThresholdValue, verts, cNode);
}
if (Array.IndexOf(verts, cNode) + width < verts.Length)
{
CheckIfQueueNeighbor(Array.IndexOf(verts, cNode) + width, heightThresholdValue, verts, cNode);
}
}
float averageTraversal = (float)l.Count / (float)verts.Length;
return averageTraversal;
}
当GUILayout.Button被按下时该函数运行:
float floodFillAverageTraversal = 0f;
for (int i = 0; i < mapPreview.floodFillSampleRate; i++)
{
floodFillAverageTraversal += FloodFill.GenerateFloodFillData(mapPreview.floodFillHeightThresholdValue, mapPreview.previewMeshFilter);
mapPreview.maps[mapPreview.mapIndexSelector].heightMapSettings.noiseSettings.seed = Random.Range(0, int.MaxValue);
mapPreview.DrawMapInEditor();
}
floodFillAverageTraversal /= mapPreview.floodFillSampleRate;
【问题讨论】:
-
不相关但普遍的问题:为什么
cNode = q.Peek(); q.Dequeue();而不是直接cNode = q.Dequeue();? ...我也看不到您在代码中使用X的位置...您能解释一下您的意思吗? -
将 X 固定到适当的变量(如果您没有看到)
-
您的代码中是否有
try-catch,而 catch 不会打印出错误?
标签: c# unity3d while-loop infinite-loop flood-fill