ToB企服应用市场:ToB评测及商务社交产业平台

标题: 如何在其他线程中安全地调用Unity的API? [打印本页]

作者: 莫张周刘王    时间: 2024-8-9 04:55
标题: 如何在其他线程中安全地调用Unity的API?
前言


        Unity的大部分API(例如,与游戏对象交互,修改组件属性等)都需要在主线程中调用。然而,偶然你可能在另一个线程(例如,网络请求,长时间运行的盘算等)中完成一些工作,并且在完成后需要更新Unity的某些东西。在这种情况下,你不能直接从那个线程调用Unity API,因为这可能会导致未定义的举动或错误。
        虽然你可以在其他线程中举行盘算麋集型的使命(例如,AI盘算,物理模拟等),但是你不能在其他线程中直接调用Unity的API。因此你需要类似DwkUnityMainThreadDispatcher如许的类,它可以让你在其他线程中安全地调用Unity的API。
        例如,你可以如许使用它:
 
  1. DwkUnityMainThreadDispatcher.Instance().Enqueue(() =>
  2. {
  3.     // 在这里调用Unity API
  4. });
复制代码
 
UnityMainThreadDispatcher类代码


        DwkUnityMainThreadDispatcher类原貌:

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class DwkUnityMainThreadDispatcher : MonoBehaviour
  5. {
  6.     private static DwkUnityMainThreadDispatcher instance;
  7.     private readonly Queue<System.Action> actions = new Queue<System.Action>();
  8.     private void Awake()
  9.     {
  10.         if (instance == null)
  11.         {
  12.             instance = this;
  13.             DontDestroyOnLoad(gameObject);
  14.         }
  15.         else
  16.         {
  17.             Destroy(gameObject);
  18.         }
  19.     }
  20.     public static DwkUnityMainThreadDispatcher Instance()
  21.     {
  22.         if (!instance)
  23.         {
  24.             throw new System.Exception("UnityMainThreadDispatcher could not find the UnityMainThreadDispatcher object. Please ensure you have added the MainThreadExecutor Prefab to your scene.");
  25.         }
  26.         return instance;
  27.     }
  28.     public void Enqueue(System.Action action)
  29.     {
  30.         lock (actions)
  31.         {
  32.             actions.Enqueue(action);
  33.         }
  34.     }
  35.     public void Update()
  36.     {
  37.         while (actions.Count > 0)
  38.         {
  39.             actions.Dequeue().Invoke();
  40.         }
  41.     }
  42. }
复制代码

举例:在非主线程中播放Unity声音


  1.         if (sum > 0)
  2.         {
  3.             DwkUnityMainThreadDispatcher.Instance().Enqueue(() =>
  4.             {
  5.                 audioSource1.PlayOneShot(audioSource1.clip);
  6.             });
  7.             //Debug.Log("加分特效");
  8.         }
复制代码

附录:


实现单例模式的标准流程


  1. private static DwkUnityMainThreadDispatcher instance;
  2. private void Awake()
  3. {
  4.     if (instance == null)
  5.     {
  6.         instance = this;
  7.         DontDestroyOnLoad(gameObject);
  8.     }
  9.     else
  10.     {
  11.         Destroy(gameObject);
  12.     }
  13. }
  14. public static DwkUnityMainThreadDispatcher Instance()
  15. {
  16.     if (!instance)
  17.     {
  18.         throw new System.Exception("UnityMainThreadDispatcher could not find the UnityMainThreadDispatcher object. Please ensure you have added the MainThreadExecutor Prefab to your scene.");
  19.     }
  20.     return instance;
  21. }
复制代码

        这个单例模式的实现步骤如下:


        这种方式的单例模式在Unity中很常见,因为它可以确保在整个游戏运行期间,只有一个DwkUnityMainThreadDispatcher实例存在,而且可以在任何地方通过DwkUnityMainThreadDispatcher.Instance()访问这个实例。

允许其他线程将使命安全地调度到主线程中执行


  1. private readonly Queue<System.Action> actions = new Queue<System.Action>();
  2. public void Enqueue(System.Action action)
  3. {
  4.     lock (actions)
  5.     {
  6.         actions.Enqueue(action);
  7.     }
  8. }
  9. public void Update()
  10. {
  11.     while (actions.Count > 0)
  12.     {
  13.         actions.Dequeue().Invoke();
  14.     }
  15. }
复制代码

 
        如许,你就可以在其他线程中安全地调度使命到主线程中执行了。这对于在其他线程中举行一些耗时的操作,然后需要更新Unity的某些东西(例如,更新UI,创建游戏对象等)非常有效。


        这部分代码提供了一种在主线程中安全执行使命的方式。你可以在任何线程中使用Enqueue方法来添加一个使命,这个使命将在主线程中执行。如许,你就可以安全地从任何线程调用Unity API了。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4