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!