C# 从线程更改主线程的游戏对象

C# 从线程更改主线程的游戏对象,c#,multithreading,unity3d,interface,listener,C#,Multithreading,Unity3d,Interface,Listener,我想以某种方式从异步线程更改游戏对象。我需要保留侦听器/接口架构 下面我创建了一个当前实现的简单示例 主脚本: using UnityEngine; public class MyScript : MonoBehaviour, IMyComponentListener { public GameObject cube; private MyComponent _myComponent; private void Start() { _myCo

我想以某种方式从异步线程更改游戏对象。我需要保留侦听器/接口架构

下面我创建了一个当前实现的简单示例

主脚本:

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)

很明显,我不能从异步线程更改主线程元素,但如何解决它或正确实现支持此功能的体系结构?

我已经找到了使用外部组件的解决方法

遵循以下步骤后,我已将我的调度程序更新为下面的示例,并作为charm工作

线程脚本:

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());
    }
}

我已经找到了一个使用外部组件的解决方案

遵循以下步骤后,我已将我的调度程序更新为下面的示例,并作为charm工作

线程脚本:

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());
    }
}

这只是一个例子,因为你要求它

一般来说,链接中的
UnityMainThreadDispatcher
就可以了

无论如何,它只是以
Update
方法处理队列。我不想使用这种单例模式解决方案,而只是在已有的
monobhavior
组件中做同样的事情(在大多数情况下,单例只是一种快速但肮脏的解决方案)

问题可能是这里的排版。。或者您可以将该方法添加到接口中


如果您有多个侦听器(由于接口的原因),我也会使用您的方式,可能仍然没有单个侦听器,而是使用适当的引用,例如通过Inspector



在我的智能手机上输入,所以没有保修,但我希望我能清楚地表明我的观点,这只是一个例子,因为你要求这样做

一般来说,链接中的
UnityMainThreadDispatcher
就可以了

无论如何,它只是以
Update
方法处理队列。我不想使用这种单例模式解决方案,而只是在已有的
monobhavior
组件中做同样的事情(在大多数情况下,单例只是一种快速但肮脏的解决方案)

问题可能是这里的排版。。或者您可以将该方法添加到接口中


如果您有多个侦听器(由于接口的原因),我也会使用您的方式,可能仍然没有单个侦听器,而是使用适当的引用,例如通过Inspector



在我的智能手机上输入,因此不提供保修,但我希望我能清楚地表明我的观点

也许能解决您的问题。如果没有,你可以看看闪亮,新的也许会解决你的问题。如果不是的话,您可以看看shiny,new,您可以直接将它实现到您的
monobhavior
类中,而不是使用单例模式。如果您另外使用了
ConcurrentQueue
,您也可以摆脱
@derHugo,您介意回答一个代码示例吗?不过,您可以直接将它实现到
monobhavior
类中,而不是使用单例模式。如果您另外使用了
ConcurrentQueue
,您也可以摆脱
@derHugo,您介意回答一个代码示例吗?不客气:)此设置基本上适用于我,例如TCP客户机/服务器。优点是您现在可以禁用该行为,队列操作系统不会进一步执行。不客气:)此设置基本上适用于我,例如TCP客户端/服务器。优点是您现在可以禁用该行为,并且队列操作系统不会进一步执行。
((MyScript)_listener).ThreadCompleted();