首页 > 解决方案 > UNET 传输级 API 高效的消息处理和类型

问题描述

和我的一个朋友一起,我们已经开始使用 Unity 游戏引擎提供的 Transport Level API (UNET LLAPI?) 开发多人游戏。

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

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

我相信这是由于用于不同数据消息的字符串变量类型。因此,我的主要问题是如何以每条消息的最大效率利用 Unity 的传输级别 API 数据事件(在这种情况下,我们只说可以在 3d 空间(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教程)

标签: c#unity3dunity-networking

解决方案


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

资源


推荐阅读