背景
有些属性或方法只能在主线程中调用,如 .gameObject
、Instantiate()
等。这是 Unity 设计时的一个缺陷(为了保证线程安全),多年来一直没有修正,或者说官方懒得弄。
以 Instantiate()
为例,在非主线程调用时,报错大概如下所示。其他属性或方法的报错也大体相同。
UnityEngine.UnityException: Internal_CloneSingle can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
at (wrapper managed-to-native) UnityEngine.Object.Internal_CloneSingle(UnityEngine.Object)
at UnityEngine.Object.Instantiate[T] (T original) [0x00012] in <25586dd8e41845059c446f7ba2bf37e4>:0
at ... (...) [0x0000a] in ... .cs:...
UnityEngine.Debug:Log (object)
注:应注意,此问题在有些情况下 Unity 控制台不会提示任何错误,只是代码会在那里中断,这时可能会让人非常摸不着头脑。使用 try { } catch (Exception e) { Debug.Log(e); }
才能在控制台中显示出错误,以便验证是不是本文所述问题。
解决方法
使用第三方包:https://github.com/PimDeWitte/UnityMainThreadDispatcher.git
步骤 1
导入包:
- 在 Unity 中,Window -> Package Manager -> 加号 -> Add package from git URL,输入上面的仓库地址,Add。
或者:
- 修改 Packages\manifest.json,在 dependencies 中加入一行:
"dependencies": {
"com.pimdewitte.unitymainthreaddispatcher": "https://github.com/PimDeWitte/UnityMainThreadDispatcher.git",
}
步骤 2
在场景内创建一个空物体,挂载 UnityMainThreadDispatcher
组件。
步骤 3
在你的代码中,按照下面的方法调用原来出问题的语句,问题解决。
普通:文章来源:https://www.toymoban.com/news/detail-799142.html
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
// 只能在主线程执行的语句
// ...
});
协程:文章来源地址https://www.toymoban.com/news/detail-799142.html
private IEnumerator Do()
{
// 只能在主线程执行的语句
// ...
yield return null;
}
private void Fun()
{
UnityMainThreadDispatcher.Instance().Enqueue(Do());
}
参考资料
- https://forum.unity.com/threads/working-with-threads-can-only-be-called-from-the-main-thread.513899/#post-7779918
- https://github.com/PimDeWitte/UnityMainThreadDispatcher
到了这里,关于Unity 解决 “... can only be called from the main thread” 问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!