为了账号安全,请及时绑定邮箱和手机立即绑定

从 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 关注
  • 157 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号