好的,我会尽我所能来解释这一点。我整天都在搜索并寻找解决此问题的方法,但似乎找不到它。我遇到的问题是,我有一个可脚本编写的对象列表,基本上可以用于自定义属性来创建游戏对象。我需要获得的那些属性之一是变成了精灵的Texture2D。因此,我在协程中使用UnityWebRequest,并且必须产生响应。得到响应后,我尝试设置变量。但是,即使在使用Lambda时,在我看来,如果我在结果之前返回return响应,也不会设置变量。因此,每次我在协程之后检查变量时,它都会返回null。如果有人可以用我在这里所缺少的东西启发我,那太好了!
这是我正在使用的脚本对象类。
[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;
}
这里是协程的呼叫
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));
}
}
答案 0 :(得分:1)
从您的需求来看,例程结束后似乎仍然以某种方式处理了纹理。我的猜测是它的发生是由于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);
}
}
因此,您也可以跟踪纹理本身,让它不被GC收集,但也可以在不再需要时销毁它。通常,Texture2D
会在不再引用时被GC删除,但是Texture2D
创建的UnityWebRequest
的行为可能会有所不同。
比在webrequest中返回纹理并且不要使用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);
})
);
}
答案 1 :(得分:0)
问题出在代码的这一部分:
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;
}));
}