亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

從 Thread 更改主線程的 GameObject

從 Thread 更改主線程的 GameObject

C#
搖曳的薔薇 2022-11-13 14:33:11
我想以某種方式從異步線程更改游戲對象。我需要保留監聽器/接口架構。下面我創建了一個我當前實現的簡單示例。主腳本:using UnityEngine;public class MyScript : MonoBehaviour, IMyComponentListener{    public GameObject cube;    private MyComponent _myComponent;    private void Start()    {        _myComponent = new MyComponent(this);    }    public void OnThreadCompleted()    {        cube.transform.Rotate(Vector3.up, 10f);    }}線程腳本:using System.Threading;public class MyComponent{    private readonly IMyComponentListener _listener;    public MyComponent(IMyComponentListener listener)    {        _listener = listener;        Thread myThread = new Thread(Run);        myThread.Start();    }    private void Run()    {        Thread.Sleep(1000);        _listener.OnThreadCompleted();    }}監聽接口:public interface IMyComponentListener{    void OnThreadCompleted();}如果我嘗試此代碼,我將面臨以下錯誤:get_transform 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.UnityEngine.GameObject:get_transform()MyScript:OnThreadCompleted() (at Assets/Scripts/MyScript.cs:18)MyComponent:Run() (at Assets/Scripts/MyComponent.cs:20)很明顯我不能從異步線程更改主線程元素,但我該如何解決它或正確實現支持它的架構?
查看完整描述

2 回答

?
慕森卡

TA貢獻1806條經驗 獲得超8個贊

這只是一個例子,因為你要求它。


一般來說,UnityMainThreadDispatcher來自您的鏈接很好。


無論如何,它只是在一種Update方法中處理隊列。我不想使用這個 Singleton-Pattern 解決方案,而只是在MonoBehaviour您已有的組件中做同樣的事情(Singleton 在大多數情況下只是一個快速但骯臟的解決方案)


public class MyScript : MonoBehaviour, IMyComponentListener

{

    public GameObject cube;


    private MyComponent _myComponent;


    private ConcurrentQueue<Action> callbacks = new ConcurrentQueue<Action>();


    private void Start()

    {

        _myComponent = new MyComponent(this);

    }


    // Work the callbacks queue

    private void Update()

    {

        if(callbacks.Count == 0) return;


        while(callbacks.Count != 0)

        {

            Action a;

            if(!callbacks.TryDequeue(out a)) continue;


            a.Invoke();

        }

    }


    public void ThreadCompleted()

    {

        callbacks.Enqueue(OnThreadCompleted);

    }


    private void OnThreadCompleted()

    {

        cube.transform.Rotate(Vector3.up, 10f);

    }

}

而不是你會打電話enqueue給那個,而不是像


((MyScript)_listener).ThreadCompleted();

問題可能是這里的類型轉換..或者您可以將方法添加到接口。


如果您有多個偵聽器(似乎是由于界面),我也會使用您的方式,可能仍然沒有單例,而是使用適當的引用,例如通過 Inspector。


在我的智能手機上打字,所以沒有保修,但我希望我能表達清楚


查看完整回答
反對 回復 2022-11-13
?
SMILET

TA貢獻1796條經驗 獲得超4個贊

我想出了一個使用外部組件UnityMainThreadDispatcher的解決方法。

按照安裝說明進行操作后,我已將調度程序更新為以下示例并發揮了魅力!

線程腳本:

using System.Threading;


public class MyComponent

{

    private readonly IMyComponentListener _listener;


    public MyComponent(IMyComponentListener listener)

    {

        _listener = listener;


        Thread myThread = new Thread(Run);


        myThread.Start();

    }


    private void Run()

    {

        Thread.Sleep(1000);


        UnityMainThreadDispatcher.Instance().Enqueue(() => _listener.OnThreadCompleted());

    }

}


查看完整回答
反對 回復 2022-11-13
  • 2 回答
  • 0 關注
  • 121 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號