c# - 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教程)
解决方案
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);
推荐阅读
- android - 当应用程序从前台被杀死时在 Ionic 应用程序中显示通知
- java - 如何从 RecyclerView Android 中的编辑文本中获取价值
- flutter - 在 Flutter 中重新实例化 Provider 创建的类
- swift - 我的代码中出现 Pthread 终止错误,不知道为什么。// swift
- ruby-on-rails - 如何在多列上内联索引
- sqlite - 使用 DropdownButton 值
- spring-mvc - 在 gradle 项目中部署 SpringMvcPortlet
- vb.net - 未创建 SQLite 数据库创建
- r - 需要帮助将带有引用和标题的 Word 文件导入 R
- python - 如何使命令仅在另一个 discord.py 之后可用