扬州集团网站建设,百度网站排名突然消失,专业网站建设制作公司,做app护肤网站前言 Unity的大部分API#xff08;例如#xff0c;与游戏对象交互#xff0c;修改组件属性等#xff09;都需要在主线程中调用。然而#xff0c;有时你可能在另一个线程#xff08;例如#xff0c;网络请求#xff0c;长时间运行的计算等#xff09;中完成一些工作例如与游戏对象交互修改组件属性等都需要在主线程中调用。然而有时你可能在另一个线程例如网络请求长时间运行的计算等中完成一些工作并且在完成后需要更新Unity的某些东西。在这种情况下你不能直接从那个线程调用Unity API因为这可能会导致未定义的行为或错误。 虽然你可以在其他线程中进行计算密集型的任务例如AI计算物理模拟等但是你不能在其他线程中直接调用Unity的API。因此你需要类似DwkUnityMainThreadDispatcher这样的类它可以让你在其他线程中安全地调用Unity的API。 例如你可以这样使用它 DwkUnityMainThreadDispatcher.Instance().Enqueue(()
{// 在这里调用Unity API
}); UnityMainThreadDispatcher类代码 DwkUnityMainThreadDispatcher类原貌 using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class DwkUnityMainThreadDispatcher : MonoBehaviour
{private static DwkUnityMainThreadDispatcher instance;private readonly QueueSystem.Action actions new QueueSystem.Action();private void Awake(){if (instance null){instance this;DontDestroyOnLoad(gameObject);}else{Destroy(gameObject);}}public static DwkUnityMainThreadDispatcher Instance(){if (!instance){throw new System.Exception(UnityMainThreadDispatcher could not find the UnityMainThreadDispatcher object. Please ensure you have added the MainThreadExecutor Prefab to your scene.);}return instance;}public void Enqueue(System.Action action){lock (actions){actions.Enqueue(action);}}public void Update(){while (actions.Count 0){actions.Dequeue().Invoke();}}
}举例在非主线程中播放Unity声音 if (sum 0){DwkUnityMainThreadDispatcher.Instance().Enqueue(() {audioSource1.PlayOneShot(audioSource1.clip);});//Debug.Log(加分特效);} 附录 实现单例模式的标准流程 private static DwkUnityMainThreadDispatcher instance;private void Awake()
{if (instance null){instance this;DontDestroyOnLoad(gameObject);}else{Destroy(gameObject);}
}public static DwkUnityMainThreadDispatcher Instance()
{if (!instance){throw new System.Exception(UnityMainThreadDispatcher could not find the UnityMainThreadDispatcher object. Please ensure you have added the MainThreadExecutor Prefab to your scene.);}return instance;
} 这个单例模式的实现步骤如下 声明一个私有静态变量instance来存储单例实例。 在Awake()方法中检查instance是否为null。如果为null则将instance设置为当前实例并使用DontDestroyOnLoad(gameObject)确保在加载新场景时不会销毁这个对象。如果instance不为null则销毁当前游戏对象这样可以确保只有一个DwkUnityMainThreadDispatcher实例存在。 提供一个公共静态方法Instance()来获取单例实例。如果instance为null则抛出一个异常提示用户需要在场景中添加MainThreadExecutor Prefab。 这种方式的单例模式在Unity中很常见因为它可以确保在整个游戏运行期间只有一个DwkUnityMainThreadDispatcher实例存在而且可以在任何地方通过DwkUnityMainThreadDispatcher.Instance()访问这个实例。 允许其他线程将任务安全地调度到主线程中执行 private readonly QueueSystem.Action actions new QueueSystem.Action();public void Enqueue(System.Action action)
{lock (actions){actions.Enqueue(action);}
}public void Update()
{while (actions.Count 0){actions.Dequeue().Invoke();}
} 在其他线程中当你需要执行一些必须在主线程中进行的操作例如调用Unity的API时你可以创建一个System.Action这个System.Action包含了你想要执行的操作。 你将这个System.Action传递给Enqueue方法。Enqueue方法将这个System.Action添加到actions队列中。这个过程是线程安全的因为Enqueue方法使用了lock关键字来确保在多线程环境下添加任务到队列的操作是线程安全的。 在主线程中Unity每一帧都会调用Update方法。在Update方法中它会检查actions队列中是否有任务。如果有它会使用Dequeue方法取出队列中的第一个任务并使用Invoke方法执行这个任务。这个过程会一直进行直到actions队列中没有任务为止。 这样你就可以在其他线程中安全地调度任务到主线程中执行了。这对于在其他线程中进行一些耗时的操作然后需要更新Unity的某些东西例如更新UI创建游戏对象等非常有用。 private readonly QueueSystem.Action actions new QueueSystem.Action(); 这行代码创建了一个队列用于存储要在主线程中执行的任务。每个任务都是一个System.Action也就是一个无参数且无返回值的委托。 public void Enqueue(System.Action action) 这个方法用于将一个任务添加到队列中。这个任务将在主线程中执行。lock (actions)这行代码确保了在多线程环境下添加任务到队列的操作是线程安全的。 public void Update() 这个方法在每一帧都会被Unity调用它在主线程中执行。在这个方法中它会执行队列中的所有任务。这是通过在队列中有任务时调用actions.Dequeue().Invoke()来实现的。Dequeue()方法移除并返回队列中的第一个任务Invoke()方法则执行这个任务。 这部分代码提供了一种在主线程中安全执行任务的方式。你可以在任何线程中使用Enqueue方法来添加一个任务这个任务将在主线程中执行。这样你就可以安全地从任何线程调用Unity API了。