我遇到的问题是,使用Unity制作的多人射击游戏的网络延迟较低。我正在使用UDP将玩家位置从游戏客户端发送到我的亚马逊服务器并返回到另一个游戏客户端。我的游戏客户端以每秒8个数据包的速率向亚马逊服务器发送60字节的UDP数据包。
当我在两个独立的iOS设备(iPhone 7和iPad mini)上玩游戏时,网络延迟非常低,玩家可以立即看到对方移动。但是,如果我在iPhone 7上运行游戏并与使用运行android的三星galaxy s4的另一个玩家玩,这是一个低功率设备,当我从iOS设备接收玩家位置时,我在Android设备上遇到5秒延迟。奇怪的是iOS设备可以立即从Android设备接收玩家位置。在iPhone 7上针对Mac上的客户端玩iPhone时会出现同样的问题,除了iPhone 7在从mac客户端接收玩家位置时遇到5秒的延迟。当在三星Galaxy S4上与Mac上的客户端玩游戏时,也会出现这个问题,其中galaxy s4经历了5秒的延迟。
我曾尝试将udp接收缓冲区大小增加到16 MB,但它没有改变任何内容。
以下是我的游戏客户端代码示例,我将玩家位置发送到亚马逊服务器:
@CacheEvict
以下是我的游戏客户端中的UDP发送者类的示例:
void Update(){
// manually constrain rotation because rigidbody constraints don't work
this.transform.rotation = Quaternion.Euler(new Vector3(0, this.transform.rotation.eulerAngles.y, 0));
this.transform.position = new Vector3(this.transform.position.x, boatHeightConstant, this.transform.position.z);
// Speed Boost Handling
if(isSpeedBoosting == true){
tiltFactor = tiltModifier * (VelocityRatio() + 1.0f);
speedBoostTimer += Time.deltaTime;
}
else{
tiltFactor = VelocityRatio() + 1.0f;
}
if(speedBoostTimer >= speedBoostDuration){
isSpeedBoosting = false;
speedBoostTimer = 0f;
endSpeedBoost = true;
}
if(endSpeedBoost == true){
GetComponentInChildren<MainWeapon>().EndFireRateBoost();
endSpeedBoost = false;
}
// Attack Boost Handling
if(isAttackBoosting == true){
attackBoostTimer += Time.deltaTime;
}
if(attackBoostTimer >= attackBoostDuration){
isAttackBoosting = false;
attackBoostTimer = 0f;
endAttackBoost = true;
}
if(endAttackBoost == true){
GetComponentInChildren<MainWeapon>().ResetDamage();
GetComponentInChildren<MainWeapon>().ResetHeatUpRate();
endAttackBoost = false;
}
if (GetComponent<InputManager>().GetInputType() == 0 || GetComponent<InputManager>().GetInputType() == 1 )
{
if (isSpeedBoosting == true)
{
Move(speedModifier);
}
else
{
Move(1f);
}
if (syncTimer <= 0f) {
syncTimer = networkRefreshRate;
SyncTransform ();
} else {
syncTimer -= Time.deltaTime;
}
}
else
{
NetworkMove();
}
}
/// <summary>
/// This function is constantly called to upload the local player's position to the server so the server is
/// aware of this player's movement and can share this local players current position with other players in the game.
/// </summary>
public void SyncTransform() {
if (isLocalPlayer == true && client != null && client.IsConnected()) {
client.SendPlayerTransform(SharedData.storage["userId"], transform.position, transform.rotation, currentLife);
}
}
以下是我在游戏客户端上收到UDP消息的示例:
public void SendPlayerTransform(string playerId, Vector3 position, Quaternion rotation, int currentLife) {
Message.Writer writer = new Message.Writer(Message.MessageType.PlayerTransform, udpClient, remoteEndPoint);
// Write the timestamp of this message
writer.WriteLong(DateTime.UtcNow.Ticks);
// write the player id
writer.WriteString(SharedData.storage["userId"]);
// write the position vector
writer.WriteFloatArray(CommonGameFunctions.ConvertVectorToFloatArray(position));
// write the rotation vector
writer.WriteFloatArray(CommonGameFunctions.ConvertQuaternionToFloatArray(rotation));
writer.WriteInt (currentLife);
// Now send the message
writer.Send();
}
在我的服务器上,这是主游戏循环,它在自己的专用线程上运行。
public int HandleUdpMessages() {
if (udpTimerStarted == false) {
lastUdpMessageReceivedTime = DateTime.Now;
udpTimerStarted = true;
} else if (udpTimerStarted == true && udpClient.Available == 0){
TimeSpan t = DateTime.Now - lastUdpMessageReceivedTime;
if (t.Seconds >= 10f) {
// no message received for last 10 seconds then throw IO exception
//throw new SocketException();
}
}
if (udpClient.Available > 0) {
var messageReader = new Message.Reader (udpClient);
messageReader.BlockingRead (ref localEndPoint, UdpReceiveTimeout);
var messageType = messageReader.ReadMessageTypeUdp ();
lastUdpMessageReceivedTime = DateTime.Now;
Debug.Log ("Received udp message: " + messageType);
switch (messageType) {
// Player position update message
case Message.MessageType.PlayerTransform:
HandlePlayerTransform (messageReader);
break;
case Message.MessageType.PlayerScore:
HandlePlayerScore (messageReader);
break;
case Message.MessageType.RockHealth:
HandleRockHealth (messageReader);
break;
case Message.MessageType.PlayerHealth:
HandlePlayerHealth (messageReader);
break;
case Message.MessageType.ShieldHealth:
HandleShieldHealth (messageReader);
break;
default:
Debug.LogError ("Unhandled message " + messageType);
break;
}
}
return 0;
}
public void HandlePlayerTransform(Message.Reader reader)
{
long timeStamp = reader.ReadLong ();
string playerId = reader.ReadString();
if (playerMessageTimeStamps [playerId].latestPlayerTransform > timeStamp)
return;
Vector3 position = new Vector3();
Quaternion rotation = new Quaternion();
// read position
position = CommonGameFunctions.ConvertFloatArrayToVector3(reader.ReadFloatArray(3));
rotation = CommonGameFunctions.ConvertFloatArrayToQuaternion(reader.ReadFloatArray(4));
// Now update the transform of the right player
Player player = Player.playerTable[playerId];
if (player == null) {
return;
}
player.SetNetworkPostion(position);
player.SetNetworkRotation(rotation);
}
答案 0 :(得分:0)
所以我想出了我的代码的问题。我在udp消息处理函数的每次迭代中只读取了一条udp消息。我改变了我的函数来读取缓冲区中所有可用的udp消息,并且滞后减少了80%。 UDP消息在缓冲区中排队比消息处理程序函数重复更快,因此这就是问题发生的原因。