UNET 传输级别 API 高效的消息处理和类型

UNET Transport Level API Efficient Message Handling and Types

与我的一个朋友一起,我们已经开始使用 Unity 游戏引擎提供的传输级别 API (UNET LLAPI?) 开发一款多人游戏。

因为需要在其他玩家的视野范围内有多达一百个并发用户,所以我想知道发送有关玩家位置、旋转等消息的最有效方式是什么。

到目前为止,根据 Youtube 上的教程 (1),我们能够建立一个系统,其中仅更新不同 moving 玩家的位置。然而,即使只有 5 个玩家同时移动,位置更新也会在不同的客户端上出现超级延迟。

我认为这是由于用于不同数据消息的字符串变量类型所致。因此,我的主要问题是如何以每条消息的最大效率利用 Unity 的传输级别 API 数据事件(在这种情况下,我们只说位置更新,其中可以在 3d space 的任何方向上移动) (x,y,z))

这是我们为服务器脚本准备的代码... 就像在调用正确函数之前的教程中一样,每个消息字符串都用适当的分隔符分隔,分隔从客户端接收的参数。客户端有一个类似的消息接收系统,但功能不同。代码下面的代码当然是在服务器脚本的更新功能中。

NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
    switch (recData)
    {
        case NetworkEventType.Nothing:
            break;
        case NetworkEventType.ConnectEvent:
            Debug.Log("Player " + connectionId + " has connected");
            OnConnection(connectionId);
            break;
        case NetworkEventType.DataEvent:
            string msg = Encoding.Unicode.GetString(recBuffer, 0, dataSize);
            Debug.Log("Receving from " + connectionId + " : " + msg);
            string[] splitData = msg.Split('|');

            switch (splitData[0])
            {
                case "NAMEIS":
                    OnNameIs(connectionId, splitData[1]);
                    break;

                case "MYPOSITION":
                    OnMyPosition(connectionId, float.Parse(splitData[1]), float.Parse(splitData[2]), float.Parse(splitData[3]));
                    break;

                case "MOVESELECT":
                    OnMoveSelect(connectionId, bool.Parse(splitData[1]), new Vector3(float.Parse(splitData[2]), float.Parse(splitData[3]), float.Parse(splitData[4])));
                    break;
                case "NEWPLAYERSTARTED":
                    OnNewPlayerStarted(connectionId);
                    break;
                case "POSITIONTOANOTHER":
                    OnPositionToAnother(connectionId, float.Parse(splitData[1]), float.Parse(splitData[2]), float.Parse(splitData[3]), int.Parse(splitData[4]));
                    break;
                default:
                    Debug.Log("invalid Message : " + msg);
                    break;
            }
            break;
        case NetworkEventType.DisconnectEvent:
            Debug.Log("Player " + connectionId + " has disconnected");
            OnDisconnection(connectionId);
            break;
        case NetworkEventType.BroadcastEvent:

            break;
    }

参考资料: 1. https://www.youtube.com/watch?v=qGkkaNkq8co(改编 UNET 教程)

NetworkTransport.Receive 使用队列,一次弹出一个项目。

与其直接在更新中执行,不如尝试将其包裹在 do while 中,这应该会提高性能

int recHostId;
int connectionId;
int channelId;
int dataSize;
byte error;
NetworkEventType recData = NetworkEventType.Nothing;
do {
    recData = NetworkTransport.Receive (out recHostId, out connectionId, out channelId, workingBuffer, workingBuffer.Length, out dataSize, out error);
    if (recData == NetworkEventType.Nothing) {
        break;
    }
    byte[] recBuffer = new byte[dataSize];

    if (dataSize > 0) {
        Buffer.BlockCopy (workingBuffer, 0, recBuffer, 0, dataSize);
    }

    // Switch statement
} while (recData != NetworkEventType.Nothing);

source