【问题标题】:Cant instantiate a prefab from another script无法从另一个脚本实例化预制件
【发布时间】:2020-01-01 04:32:14
【问题描述】:

我无法从另一个脚本实例化预制件,它什么也不做,也没有给我任何错误。在同一个“播放”中,我可以多次从同一个脚本中实例化同一个预制件,但是如果我尝试通过从另一个脚本执行相同的方法来执行它,它就不起作用....我传递了一些变量并打印它们(它工作) 但 instatiation 什么也没做......请帮忙!

我试图通过以下方式解决它:

公共游戏对象参考, UnityEvents 和 将两个脚本附加到一个对象中

脚本一

void OnEnable()
{
    EventSystemManager.StartListening("printMessage", AddMessage);     
}

public void AddMessage(string message ) 
{
    GameObject remoteMessage = Instantiate(localMessagePrefab, 
    chatTransform);
    remoteMessage.transform.GetChild(0).GetComponentInChildren<Text> 
    ().text = message;
}

脚本二

public IEnumerator StartWebSocket() 
{
    using (ws = new WebSocket(serveradress))
    {
        ws.OnOpen += (sender, e) =>
        onOpenHandler();
        ws.OnMessage += (sender, e) =>
        onMessageHandler(e.Data);
        ws.OnError += (sender, e) =>
        onErrorHandler(e);
        ws.OnClose += (sender, e) =>
        onCloseHandler(e);
        ws.Connect();
        for (; ; )
        {
            yield return null;
        }
    }
} 

private async void onMessageHandler(string e)
{
    serverMessage = JsonUtility.FromJson<serverMssg>(e);
    EventSystemManager.TriggerEvent("printMessage", 
    serverMessage.normmsg);
    await miaApi.queueAnim(serverMessage.normmsg);
}

消息已传递,但实例化什么也不做...... 我在调试中检测到的唯一一件事是,当尝试从其他脚本中进行转换时,转换消失了:

来自同一个脚本:

来自另一个脚本:

还有视频(无声) 视频不使用事件,但行为完全相同 Video 蒂亚!

【问题讨论】:

  • 经过一些测试后,我意识到我可以使用 start 方法从另一个脚本实例化,但是如果我从 onMessageHandler 方法中执行它就不起作用....
  • 我认为问题在于 websocket onMessage 是异步的.....但我没有找到让它工作的方法......我认为这些事件会解决问题...... .

标签: c# unity3d


【解决方案1】:

我不知道EventSystemManager 是如何工作的。

如果问题实际上是 async 和多线程,您可以尝试使用简单的“调度程序”将回调传递回主线程:

public class MainThreadDispatcher : MonoBehaviour
{
    private static MainThreadDispatcher _instance;
    public static MainThreadDispatcher Instance
    {
        get 
        {
            if(!_instance)
            {
                _instance = new GameObject("MainThreadDispatcher").AddComponent<MainThreadDispatcher>();

                DontDestroyOnLoad(_instance.gameObject);
            }

            return _instance;
        }
    }

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

    private void Update()
    {
        // work the queue in the main thread
        while(actions.TryDequeue(out var action))
        {
            action?.Invoke();
        }
    }

    public void Dispatch(Action action)
    {
        actions.Enqueue(action);
    }
}

然后用它来确保回调在主线程中完成

private MainThreadDispatcher mainThreadDispatcher;

void OnEnable()
{
    // before dispatching stuff make sure an instance reference is optained
    // or is created in the main thread
    mainThreadDispatcher = MainThreadDispatcher.Instance;

    EventSystemManager.StartListening("printMessage", AddMessage);   
}

// might be executed in a thread
public void AddMessage(string message ) 
{
    // instead of directly executing the code wait for the main thread
    // either using a lambda expression
    mainThreadDispatcher.Dispatch(() =>
        {
            GameObject remoteMessage = Instantiate(localMessagePrefab, 
            chatTransform);
            remoteMessage.transform.GetChild(0).GetComponentInChildren<Text> 
            ().text = message;
        });

    // or if you prefer a method
    //mainThreadDispatcher.Dispatch(HandleAddMessage);
}

// should be only executed in the main thread
private void HandleAddMessage()
{
    GameObject remoteMessage = Instantiate(localMessagePrefab, 
    chatTransform);
    remoteMessage.transform.GetChild(0).GetComponentInChildren<Text> 
    ().text = message;
}

【讨论】:

  • 这正是我所需要的。我认为我最初的问题没有很好地发布,但事实是我没有确定它与线程有关。非常感谢你,你的例子也毫无疑问!我给了你我的一票,但我的声誉仍然很低!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-31
相关资源
最近更新 更多