Unity从URL下载图片时编辑器冻结问题求助
Unity编辑器冻结原因及解决方案
冻结原因
你的代码触发了死锁,导致Unity主线程完全阻塞:
- 在
SetImage方法中调用textureTask.Result,会强制阻塞当前主线程,等待异步任务完成。 GetRemoteTexture中的await Task.Delay需要回到主线程才能继续执行后续逻辑(Unity异步上下文默认绑定主线程)。- 主线程被
Result卡死,无法处理await的回调,异步任务永远无法完成,形成循环等待的死锁,最终Unity编辑器完全冻结,连Debug.Log都无法输出(日志输出依赖主线程处理)。
另外代码存在冗余:连续调用两次Sprite.Create,第一次的结果未被使用。
修复方案
1. 用async/await替代Task.Result避免死锁
修改GenerateCard的SetImage为异步方法,同时让按钮触发的LoadSprite支持异步:
// 按钮挂载的脚本 [SerializeField] private SpriteRenderer card; [SerializeField] private string url; // Unity 2019.3+支持按钮直接调用async void方法 public async void LoadSprite() { GenerateCard setCardSprite = new GenerateCard(); await setCardSprite.SetImage(card, url); }
// GenerateCard类 public class GenerateCard { public async Task SetImage(SpriteRenderer card, string url) { Texture2D cardimage = await DownloadImages.GetRemoteTexture(url); if (cardimage == null) { Debug.LogError("加载卡牌纹理失败"); return; } Rect rec = new Rect(0, 0, cardimage.width, cardimage.height); // 仅创建一次Sprite,锚点设为中心更符合常规卡牌显示需求 Sprite cardSprite = Sprite.Create(cardimage, rec, new Vector2(0.5f, 0.5f), 100f); card.sprite = cardSprite; } }
2. 优化异步等待逻辑(可选)
原DownloadImages中的循环等待可以用更高效的方式替代,避免频繁的Task.Delay:
public class DownloadImages { public static async Task<Texture2D> GetRemoteTexture(string url) { Debug.Log("function was called"); using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(url)) { Debug.Log("begins request"); AsyncOperation asyncOp = www.SendWebRequest(); // 用TaskCompletionSource包装AsyncOperation,等待请求完成 var completionSource = new TaskCompletionSource<bool>(); asyncOp.completed += _ => completionSource.SetResult(true); await completionSource.Task; Debug.Log("finished waiting"); if (www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError) { #if DEBUG Debug.Log($"{www.error}, URL:{www.url}"); #endif return null; } else { Debug.Log("Texture downloaded"); return DownloadHandlerTexture.GetContent(www); } } } }
关键说明
- Unity是单线程模型,任何阻塞主线程的操作都会导致编辑器/游戏冻结,绝对不要在主线程中调用
Task.Result或Task.Wait()。 - 所有Unity API(如
SpriteRenderer.sprite赋值、Sprite.Create)必须在主线程执行,async/await在Unity中默认会回到主线程上下文,无需额外处理线程切换。
内容的提问来源于stack exchange,提问作者Gurkenschnitzel
相关产品推荐
相关产品推荐

