Unity freezes when I juggle Lists and SortedLists.
Hey everyone,
I have a scene full of objects - "Sites". Their positions are stored in a List < Vertex3 > siteList. I'd like to get a List < List < int > > siteNeighboursList - list of lists of neighbours - indexes of sites sorted by distance from each site.
My current code freezes Unity whenever I try to populate siteList with more than ~200 entries.
private void CreateNeighboursList()
{
var oneSiteDistancesList = new SortedList(); // key - distance; value - site index
var oneSiteSortedList = new List<int>(); //value - site index, sorted by distance
float tempDistance;
for (int i = 0; i < siteList.Count; i++)
{
oneSiteDistancesList.Clear();
oneSiteSortedList.Clear();
for (int j = 0; j < siteList.Count; j++)
{
if (i != j) // to avoid sites trying to list themselves as neighbours
{
tempDistance = Vector3.Distance(siteList[i], siteList[j]);
while (oneSiteDistancesList.ContainsKey(tempDistance)) // to avoid duplicate keys
{
tempDistance += 0.000001f;
}
oneSiteDistancesList.Add(tempDistance, j);
}
}
for (int j = 0; j < oneSiteDistancesList.Count; j++)
{
oneSiteSortedList.Add((int)oneSiteDistancesList.GetByIndex(j));
}
siteNeighbours.Add(oneSiteSortedList);
}
}
Is there something wrong with the code? Should I try different approach? Should I store the values differently?
Thanks in advance.
Can I see exactly how you have siteNeighboursList defined?
Answer by TBruce · Sep 27, 2016 at 09:27 PM
It is most likely that as you add more and more items to the oneSiteDistancesList, it eventually takes longer to go through it. Which make the while loop appear to be endless. Try using a coroutine like this instead
List<Vertex3> siteList = new List<Vertex3>(); // assuming this is how you have this defined
// moved the following two to be global
private SortedList oneSiteDistancesList = new SortedList(); // key - distance; value - site index
private List<int> oneSiteSortedList = new List<int>(); //value - site index, sorted by distance
private void CreateNeighboursList()
{
if (siteList.Count > 0)
{
float tempDistance;
for (int i = 0; i < siteList.Count; i++)
{
oneSiteDistancesList.Clear();
oneSiteSortedList.Clear();
for (int j = 0; j < siteList.Count; j++)
{
if (i != j) // to avoid sites trying to list themselves as neighbours
{
tempDistance = Vector3.Distance(siteList[i], siteList[j]);
StartCoroutine(CheckDistance(tempDistance, j));
}
}
for (int j = 0; j < oneSiteDistancesList.Count; j++)
{
oneSiteSortedList.Add((int)oneSiteDistancesList.GetByIndex(j));
}
siteNeighbours.Add(oneSiteSortedList);
}
}
}
IEnumerator CheckDistance(float tempDistance, int site)
{
while (oneSiteDistancesList.ContainsKey(tempDistance)) // to avoid duplicate keys
{
tempDistance += 0.000001f;
yield return null;
}
yield return null;
oneSiteDistancesList.Add(tempDistance, site);
}
It may still take a while to process a large number of sites, but now other processing can take place including quitting the game immediately if desired.
Edit: it seems that additions to siteNeighbours aren't being handled properly.
Wow, Coroutine helped! I haven't used them before. Here's how the code looks now:
private List<Vector3> siteList = new List<Vector3>();
private List<List<int>> siteNeighbours = new List<List<int>>();
private SortedList oneSiteDistancesList = new SortedList(); // key - distance; value - site index
private List<int> oneSiteSortedList = new List<int>(); //value - site index, sorted by distance
private void CreateNeighboursList()
{
if (siteNeighbours.Count != siteList.Count)
{
StartCoroutine(CreateNeighboursCoroutine());
}
}
IEnumerator CreateNeighboursCoroutine()
{
if (siteList.Count > 0)
{
float tempDistance;
for (int i = 0; i<siteList.Count; i++)
{
oneSiteDistancesList.Clear();
oneSiteSortedList.Clear();
Debug.Log("CreateNeighboursCoroutine: i: " + i);
yield return null;
for (int j=0; j<siteList.Count; j++)
{
if (i != j) // to avoid sites trying to list themselves as neighbours
{
tempDistance = Vector3.Distance(siteList[i], siteList[j]);
while (oneSiteDistancesList.Contains$$anonymous$$ey(tempDistance)) // to avoid duplicate keys
{
tempDistance += UnityEngine.Random.Range(0f,0.01f);
yield return null;
}
oneSiteDistancesList.Add(tempDistance, j);
}
}
for (int j = 0; j < oneSiteDistancesList.Count; j++)
{
oneSiteSortedList.Add((int)oneSiteDistancesList.GetByIndex(j));
}
siteNeighbours.Add(oneSiteSortedList);
}
}
}
Thanks again!
Your answer