need help stopping these lag spikes when my list iterates
Hey guys, I'm having trouble with something. I'm making a huge tile based procedural world, and using object pooling to keep the performance up. Now it works pretty well, but I have a script that iterates through every point and checks to see if it should place a tile at that spot. Here is what it looks like right now:
IEnumerator CheckActivation()
{
if (activatorItems.Count > 0)
{
for(int i=0;i<activatorItems.Count;i++)
{
if (Vector3.Distance(plrtransform.position, activatorItems[i].itemPos) < distanceFromPlayer)
{
if (activatorItems[i].itemName.Contains("grasstile"))
{
objectPooler.Instance.SpawnFromPool("GrassTile", activatorItems[i].itemPos, Quaternion.identity);
}
else if (activatorItems[i].itemName.Contains("sandtile"))
{
objectPooler.Instance.SpawnFromPool("SandTile", activatorItems[i].itemPos, Quaternion.identity);
}
else if (activatorItems[i].itemName.Contains("watertile"))
{
objectPooler.Instance.SpawnFromPool("WaterTile", activatorItems[i].itemPos, Quaternion.identity);
}
}
}
}
yield return new WaitForSecondsRealtime(1f);
StartCoroutine("CheckActivation");
}
}
So lets say I have a 1000x1000 tiles, so its iterating over a million tiles. And every single iteration I get a lag spike. I'm just not sure how I could clean this up to make it more performance friendly
Answer by Hellium · May 18, 2020 at 08:35 PM
So lets say I have a 1000x1000 tiles, so its iterating over a million tiles
Are you saying that activatorItems.Count
is equal to 1,000,000 ? (⊙_⊙')
A very first step would be to store the correct IDs once and reuse them in the coroutine.
private string[] spawnIDs;
private void Awake()
{
FillSpawnIDs();
}
void FillSpawnIDs()
{
if(activatorItems.Count == 0)
return ;
spawnIDs = new string[activatorItems.Count];
for(int i = 0 ; i < activatorItems.Count ; i++)
{
if (activatorItems[i].itemName.Contains("grasstile")) spawnIDs[i] = "GrassTile";
else if (activatorItems[i].itemName.Contains("sandtile")) spawnIDs[i] = "SandTile";
else if (activatorItems[i].itemName.Contains("watertile")) spawnIDs[i] = "WaterTile";
}
}
IEnumerator CheckActivation()
{
if(activatorItems.Count == 0)
return ;
WaitForSecondsRealtime wait = new WaitForSecondsRealtime(1f);
float sqrDistance = distanceFromPlayer * distanceFromPlayer;
while(true)
{
for(int i = 0 ; i < activatorItems.Count ; i++)
{
if ((plrtransform.position - activatorItems[i].itemPos).sqrDistance < sqrDistance)
objectPooler.Instance.SpawnFromPool(spawnIDs[i], activatorItems[i].itemPos, Quaternion.identity);
}
yield return wait;
}
}
But even with this small optimisation, you will have lags with 1 million objects to process. Either do the computation over several frames, or try to implement an Octree to reduce the number of tiles to loop over.
Thanks! How do you think I would split it up over several frames?
Disclaimer: I haven't tried the following code:
IEnumerator CheckActivation()
{
if(activatorItems.Count == 0)
return ;
float sqrDistance = distanceFromPlayer * distanceFromPlayer;
int processedAmountPerSecond = activatorItems.Count; // Or replace by a fixed amount such as 1000 for instance
int stopIndex = $$anonymous$$athf.CeilToInt(Time.deltaTime * processedAmountPerSecond);
while(true)
{
for(int i = 0 ; i < activatorItems.Count ; i++)
{
if(i % stopIndex == 0)
{
yield return null;
stopIndex += $$anonymous$$athf.CeilToInt(Time.deltaTime * processedAmountPerSecond);
}
if ((plrtransform.position - activatorItems[i].itemPos).sqrDistance < sqrDistance)
objectPooler.Instance.SpawnFromPool(spawnIDs[i], activatorItems[i].itemPos, Quaternion.identity);
}
}
}
Your answer
Follow this Question
Related Questions
All GameObjects list to a GameObject? 0 Answers
Make simple(or not) score list 1 Answer
List give a count of zero when it have 1 element 1 Answer
Trying to make a list that stores multiple types of data 1 Answer
How I randomise a list of signals in Unity and remove it from the list once the clip is finished? 0 Answers