0
\$\begingroup\$

I have an issue with one of my functions. I have 5 arrays that get populated through a coroutine, if all parameters are met all of them get populated at the same time and that makes the game lag and sometimes crash on android devices. These are the two functions that do that

public void StartPopulating()
    {
        if (canPopulateAnimals()) 
        {
            StartCoroutine(GetTextures("LevelAnimals", PopulateArray));
        }

        if (canPopulateArch()) 
        {
            StartCoroutine(GetTextures("LevelArchitecture", PopulateArrayArch));
        }

        if (canPopulateTech())
        {
            StartCoroutine(GetTextures("LevelTechnology", PopulateArrayTech));
        }

        if (canPopulateVeh())
        {
            StartCoroutine(GetTextures("LevelVehicles", PopulateArrayVeh));
        }

        if (canPopulateNat()) 
        {
            StartCoroutine(GetTextures("LevelNature", PopulateArrayNat));
        }
    }


    public IEnumerator GetTextures(string _dirname,Action<Texture2D[]> onLoaded)
    {
        var fileNames = Directory.GetFiles(Application.persistentDataPath + "/" + _dirname, "*.jpg");
        Array.Sort(fileNames, (s1, s2) => Path.GetFileName(s1).CompareTo(Path.GetFileName(s2)));
        var textures = new Texture2D[fileNames.Length];
        for (int i = 0; i < fileNames.Length; i++)
        {
            UnityWebRequest webRequest = UnityWebRequestTexture.GetTexture("file://" + fileNames[i]);

            yield return webRequest.SendWebRequest();
            if (webRequest.isNetworkError || webRequest.isHttpError)
            {
                Debug.Log(webRequest.error);
            }
            else
            {
                textures[i] = DownloadHandlerTexture.GetContent(webRequest);
                status++;
            }
            done = true;
        }
        onLoaded(textures);
    }

Now i was told that i could fill a dictionary instead and Fill that in StartPopulating() and then pass that as the parameter to GetTextures() and then go through the listings one at a time but to be honest i have no idea how to do that.

so initially i created a Dictionary

public Dictionary<string, Action<Texture2D[]>> sets;

But have no clue as to how to place that into the function and enumerator , Any help would be appreciated thank you!

\$\endgroup\$
3
  • \$\begingroup\$ Why not make one coroutine that checks all of these conditions, and yields on the load in progress so that it doesn't start another load until that one completes? \$\endgroup\$
    – DMGregory
    Jul 5, 2021 at 11:40
  • \$\begingroup\$ so instead of having the StartPopulate() function i should have a coroutine that checks if the paramaters are true and if true to then do the loading like i do now? \$\endgroup\$
    – stratos la
    Jul 5, 2021 at 11:58
  • \$\begingroup\$ Don't ask, try. If trying fails, edit your question to report on the problem. \$\endgroup\$
    – DMGregory
    Jul 5, 2021 at 12:01

2 Answers 2

1
\$\begingroup\$

You can wait for a coroutine finish by yielding it like this:

yield return StartCoroutine(SomeCoroutine());

In your case you could make the StartPopulating() method a coroutine and yield each of the population coroutines:

public IEnumerator StartPopulating()
{
    if (canPopulateAnimals()) 
    {
        yield return StartCoroutine(GetTextures("LevelAnimals", PopulateArray));
    }

    if (canPopulateArch()) 
    {
        yield return StartCoroutine(GetTextures("LevelArchitecture", PopulateArrayArch));
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ You can even skip the nested StartCoroutine if you like, and just say yield return GetTextures(...) directly. \$\endgroup\$
    – DMGregory
    Jul 6, 2021 at 18:39
0
\$\begingroup\$

To answer your question about Dictionary - you can use dictionary like this:

Dictionary<int,Sprite> niceDictionary = new Dictionary<int, Sprite>();
... 
niceDictionary.Add(4654, someNiceSprite); // to add
...
mySprite = ((Sprite)niceDictionary[186]);  // to take out at a key 186
...
if (niceDictionary.ContainsKey(48) == true)  // to check if dictionary contains key 48
  {
    // something here
  }

note that you can use anything else instead of int or Sprite - vectors, strings, objects etc.

Now to address your problem from other angle. Your problem is that several coroutines sometimes are started at once. So just make sure that only one is running. For example add if/else statements.

Also you might want to try to change StartPopulating into coroutine, and GetTextures into simple function, thus making sure that two GetTextures are not running at the same time. (In this case you would have to make sure that StartPopulating itself is not launched twice).

\$\endgroup\$
2
  • \$\begingroup\$ Note that you don't need the (Sprite) cast in that last line. The dictionary already returns a value of type Sprite. \$\endgroup\$
    – DMGregory
    Jul 5, 2021 at 12:57
  • \$\begingroup\$ thank you for the reply , well i can do a count and increment it each time the textures load but the function StartPopulating() gets called on game load so i would need to find a way for it to not stop counting. because if i do count the textures and check if count == 1 do that if count == 2 do that etc etc , it only sets the first set of textures and once the count goes to to 2 nothing happens \$\endgroup\$
    – stratos la
    Jul 5, 2021 at 13:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .