尝试在 websocket 消息事件中无法实例化预制件

Ser*_*ild 1 c# unity-game-engine

我正在使用 Websocket-Sharp 来执行此操作。

这段代码在我使用它时可以工作,但我不能,因为我需要在收到 WebSocket 消息后发生它

static void NewPlayer(String name) 
    {
        GameObject player = Instantiate((GameObject) Resources.Load("Player Model"), Vector3.zero, Quaternion.identity) as GameObject;
        player.name = name;
        return;
    }

private void Start()
    {
        ws = new WebSocket("wss://servantchild-isu-game-2021.herokuapp.com");
        ws.Connect();
        NewPlayer("Name");
    }
Run Code Online (Sandbox Code Playgroud)

当我使用代码时不起作用(我也知道事件会触发并且调用实际方法但预制件不会实例化)

static void NewPlayer(String name) 
        {
            GameObject player = Instantiate((GameObject) Resources.Load("Player Model"), Vector3.zero, Quaternion.identity) as GameObject;
            player.name = name;
            return;
        }
private void Start()
    {
        ws = new WebSocket("wss://servantchild-isu-game-2021.herokuapp.com");
        ws.Connect();
        ws.OnMessage += (sender, e) =>
        {
    if (e.Data.StartsWith("Player Joined:"))
            {
                NewPlayer(Int32.Parse(e.Data.Split(':')[1]).ToString());
            }
    };
    }
Run Code Online (Sandbox Code Playgroud)

der*_*ugo 5

该事件OnMessage可能会在不同的线程上发生。

大多数 Unity API 都不是“线程安全”的,只能在 Unity 主线程上使用。

您可以使用调度程序模式,例如

using System.Collections.Concurrent;

...

// A thread-safe Queue (first in first out)
private readonly ConcurrentQueue<Action> _actions = new ConcurrentQueue<Action>(); 

GameObject playerPrefab; 

private void Start()
{
    playerPrefab = Resources.Load<GameObject>("Player Model");

    ws = new WebSocket("wss://servantchild-isu-game-2021.herokuapp.com");
    ws.Connect();
    ws.OnMessage += (sender, e) =>
    {
        Debug.Log($"Received: {e.Data}");
        if (e.Data.StartsWith("Player Joined:"))
        {
            // Do the expensive stuff still in a separate thread/task
            var value = Int32.Parse(e.Data.Split(':')[1]).ToString();
            // Dispatch into the Unity main thread's next Update routine
            _actions.Enqueue(() => NewPlayer(value));
        }
    };
}

private void Update ()
{
    // Work the dispatched actions on the Unity main thread
    while(_actions.Count > 0)
    {
        if(_actions.TryDequeue(out var action))
        {
            action?.Invoke();
        }
    }
}

private static void NewPlayer(string name) 
{
    var player = Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);
    player.name = name;
}
Run Code Online (Sandbox Code Playgroud)