Как установить переменную внутри сопрограммы после получения веб-запроса - PullRequest
0 голосов
/ 01 февраля 2019

Хорошо, я постараюсь объяснить это в меру своих возможностей.Я искал и искал весь день для решения этой проблемы, но не могу найти его.Проблема, с которой я сталкиваюсь, заключается в том, что у меня есть список объектов сценариев, которые я в основном использую для пользовательских свойств для создания игровых объектов.Одним из тех свойств, которые мне нужно получить, является Texture2D, который я превращаю в спрайт.Поэтому я использую UnityWebRequest в сопрограмме и должен дать ответ.После получения ответа я пытаюсь установить переменную.Однако, даже используя Lambdas, мне кажется, что если я верну ответ до результата, он не установит переменную.Так что каждый раз, когда я проверяю переменную после Coroutine, она возвращается null.Если бы кто-то мог просветить меня тем, чего я здесь упускаю, это было бы просто замечательно!

Вот класс Scriptable Object, который я использую.

[CreateAssetMenu(fileName = "new movie",menuName = "movie")]
public class MovieTemplate : ScriptableObject
{
    public string Title;
    public string Description;
    public string ImgURL;
    public string mainURL;
    public string secondaryURL;
    public Sprite thumbnail;
}

Вот вызов Coroutine

foreach (var item in nodes)
{
    templates.Add(GetMovieData(item));
}

foreach (MovieTemplate movie in templates)
{
   StartCoroutine(GetMovieImage(movie.ImgURL, result => 
   {
       movie.thumbnail = result;
   }));
}

Вот и сам сопрограмма

IEnumerator GetMovieImage(string url, System.Action<Sprite> result)
{
    using (UnityWebRequest web = UnityWebRequestTexture.GetTexture(url))
    {
        yield return web.SendWebRequest();
        var img = DownloadHandlerTexture.GetContent(web);
        result(Sprite.Create(img, new Rect(0, 0, img.width, img.height), Vector2.zero));
    }
}

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Из того, что вы описываете, все равно кажется, что текстура как-то удаляется, как только процедура заканчивается.Я предполагаю, что это происходит из-за блока using.

Я бы сохранил исходную ссылку на текстуру

[CreateAssetMenu(fileName = "new movie",menuName = "movie")]
public class MovieTemplate : ScriptableObject
{
    public string Title;
    public string Description;
    public string ImgURL;
    public string mainURL;
    public string secondaryURL;
    public Sprite thumbnail;
    public Texture texture;

    public void SetSprite(Sprite newSprite, Texture newTexture)
    {
        if(texture) Destroy(texture);

        texture = newTexture;
        var tex = (Texture2D) texture;
        thumbnail = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
    }
}

Так что вы также можете отслеживать саму текстуру,он не должен собираться ГК, но также уничтожать его, когда он больше не нужен.Обычно Texture2D удаляется GC, как только на него больше нет ссылок, но Texture2D, созданный UnityWebRequest, может вести себя по-другому.

Чем в веб-запросе вернуть текстуру и не использоватьusing

IEnumerator GetMovieImage(string url, System.Action<Texture> result)
{
    UnityWebRequest web = UnityWebRequestTexture.GetTexture(url));

    yield return web.SendWebRequest();

    if(!web.error)
    {
        result?.Invoke(DownloadHandlerTexture.GetContent(web));
    }
    else
    {
        Debug.LogErrorFormat(this, "Download error: {0} - {1}", web.responseCode, web.error);
    }
}

и, наконец, используйте его как

for (int i = 0; i < templates.Count; i++)  
{
    int index = i;//If u use i, it will be overriden too so we make a copy of it
    StartCoroutine(
        GetMovieImage(
            templates[index].ImgURL,
            result => 
            {
                templates[index].SetSprite(result);
            })
        );
}
0 голосов
/ 01 февраля 2019

Проблема с этим разделом вашего кода:

foreach (MovieTemplate movie in templates)
{
   StartCoroutine(GetMovieImage(movie.ImgURL, result => 
   {
       movie.thumbnail = result;//wrong movie obj
   }));
}

Здесь вы потеряете ссылку на объект фильма (переопределите по foreach) до получения результата обратного вызова.

Измените егопримерно так:

foreach (int i=0;i<templates.Length;i++)  
{
   int index= i;//If u use i, it will be overriden too so we make a copy of it
   StartCoroutine(GetMovieImage(movie.ImgURL, result => 
   {
        templates[index].thumbnail = result;
   }));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...