2
votes

I have a IEnumerator function that download a image from a server, on script not attached to prefabs, it works, but on script attached to prefabs, it doesnt work.

By doesnt work i want to say that the www.SendWebRequest() never returns, i've waited for almost 10 minutes and its doesnt returns, the image has about 200kb, so the problem isn't the image size.

I already checked if the url is correct, tried to change the image, tried to re-write the function but nothing works, this is my function:

public void Set(string NomeIcone, string NomeAnalise, string idzinho, string descricaozinha, string NomeCapa)
{
    Name.text = NomeAnalise;
    ID = idzinho;
    Descricao = descricaozinha;
    Capa = NomeCapa;
    StartCoroutine(LoadLogo(NomeIcone));
}

public IEnumerator LoadLogo(string nomeArquivo)
{
    string url = PathIcone + nomeArquivo;
    print(url);

    using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(url))
    {
        yield return www.SendWebRequest();

        if (www.error == null)
        {
            Texture2D tex = new Texture2D(1, 1);
            tex = DownloadHandlerTexture.GetContent(www);
            Icon.texture = tex;
            RawImage Foto = Icon.GetComponentInChildren<RawImage>();
            Foto.SetNativeSize();
            float altura = 100 * Foto.rectTransform.rect.height / Foto.rectTransform.rect.width;
            Foto.rectTransform.sizeDelta = new Vector2(100, altura);
        }
    }
}

My prefab setup in the inspector

As you can see, my "IconeSimbolo" is a RawImage in the prefab which this script is attached

I expect to my "IconeSimbolo" texture change to the image on the server, but it never changes.

I have this same code on another script with the same setup on the inspector, on this another prefab everything works fine, but in this one it doesnt

1
Please edit your question and explain what you mean by "it doesn't work". Does it crash the editor? Does it blue screen your computer? There is currently no way for us to know what you mean by "it doesn't work". Also, please include the code you're using to create and start the LoadCapa coroutine.Ruzihm
I changed somethings, i hope its more clear now, thanks!Gabriel Sandoli
If you put an else { Debug.Log(www.error); } after the if (www.error == null) {...} do you see that line printed? From what you've told us it seems like there is no way to determine if it never returns or if there is simply an error. It's possible that it is using an unexpected PathIcone + nomeArquivo and you're getting a 404 error or something.Ruzihm
I tried to add and nothing appears on my consoleGabriel Sandoli

1 Answers

1
votes

Well it is quite simple: The Update method is not executed on assets but only on GameObject/MonoBehaviour that are active and enabled in the Scene hierachy

&rightarrow; Prefabs don't get Update calls.

Started Coroutines in Unity are executed (MoveNext) together with the Update call (or better said after it - see the Order of Execution for Event Functions)

&rightarrow; So your IEnumerator begins and actually should send and return the request ... but you never call MoveNext on it so it never realizes that the request already finished.


Somewhere you are calling the method Set. So as a workaround you could let some GameObject/MonoBehaviour execute the IEnumerator for you like e.g.

public void Set(string NomeIcone, string NomeAnalise, string idzinho, string descricaozinha, string NomeCapa, MonoBehaviour responsibleBehaviour)
{
    Name.text = NomeAnalise;
    ID = idzinho;
    Descricao = descricaozinha;
    Capa = NomeCapa;

    // This now starts the coroutine instead on the passed 
    // responsibleBehaviour and uses that ones Update calls in order to
    // move on with the IEnumerator
    responsibleBehaviour.StartCoroutine(LoadLogo(NomeIcone));
}

and in the calling script simply add this to the end of the parameters (assuming ofcourse the calling script is a MonoBehaviour)

prefab.Set(someNomeIcone, someNomeAnalise, someIdzinho, someDescricaozinha, someNomeCapa, this);

Alternatively since you made LoadLogo public anyway you can also directly use another IEnumerator in order to execute it like:

public IEnumerator LoadLogo(string NomeIcone, string NomeAnalise, string idzinho, string descricaozinha, string NomeCapa)
{
    Name.text = NomeAnalise;
    ID = idzinho;
    Descricao = descricaozinha;
    Capa = NomeCapa;

    string url = PathIcone + NomeIcone;
    print(url);

    using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(url))
    {
        yield return www.SendWebRequest();

        if (www.error == null)
        {
            Texture2D tex = new Texture2D(1, 1);
            tex = DownloadHandlerTexture.GetContent(www);
            Icon.texture = tex;
            RawImage Foto = Icon.GetComponentInChildren<RawImage>();
            Foto.SetNativeSize();
            float altura = 100 * Foto.rectTransform.rect.height / Foto.rectTransform.rect.width;
            Foto.rectTransform.sizeDelta = new Vector2(100, altura);
        }
    }
}

and then run it on a GameObject in the Scene e.g. like

public class SomeBehaviourInScene : MonoBehaviour
{
    // reference the Prefab here
    public YourPrefabScript prefab;

    // wherever you want to call this
    public void LoadPrefabLogo()
    {
        StartCoroutine(LoadPrefabLogoRoutine());
    }

    // If you want this to be called automatically
    // on app start this could also be a 
    //private IEnumerator Start()
    private IEnumerator LoadPrefabLogoRoutine()
    {
        // this also executes the LoadLogo and at 
        // the same time waits until it is finished
        yield return prefab.LoadLogo(/* Your parameters here */);

        Debug.Log("Finished");
    }
}

Or if this is about an EditorScript you could register to EditorApplication.update in order to call MoveNext on your IEnumerator.


A general sidenote: For convenience and reasons of cooperation (e.g. see here) you should get used to use English names for all methods, variables and also in your comments.