Как вы решаете высокую задержку с UDP на мобильных устройствах - PullRequest
0 голосов
/ 02 июня 2018

У меня проблема с запаздыванием сетевых задержек для моей многопользовательской игры-шутера, созданной с помощью Unity.Я использую UDP для отправки позиций игрока из игрового клиента на мой сервер amazon и обратно в другой игровой клиент.Мои игровые клиенты отправляют 60-байтовые UDP-пакеты на сервер amazon со скоростью 8 пакетов в секунду.

Когда я играю в игру на двух отдельных устройствах iOS (iPhone 7 и iPad mini), сетевая задержка очень великанизко, и игроки могут видеть, как они двигаются мгновенно.Однако, если я запускаю игру на своем iPhone 7 и играю против другого игрока, использующего Android samsung galaxy s4, который является устройством с низким энергопотреблением, я получаю 5-секундную задержку на устройстве Android при получении позиций игрока с устройства iOS,Странно то, что устройство iOS может мгновенно получать позиции игроков с устройства Android.Та же проблема возникает при игре на iPhone 7 против клиента на Mac, за исключением того, что iPhone 7 испытывает 5-секундную задержку при получении позиций игрока от клиента Mac.Эта проблема также возникает при игре на Samsung Galaxy S4 с клиентом на Mac, где время ожидания Galaxy S4 составляет 5 секунд.

Я пытался увеличить размер буфера приема udp до 16 МБ, но это не так.ничего не изменить.

Вот пример кода моего игрового клиента, куда я отправляю позиции игроков на сервер amazon:

    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 в моей игреclient:

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

}

Вот пример того, где я получаю UDP-сообщения на игровом клиенте:

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

На моем сервере это основной игровой цикл, который работает сам по себе.специальная тема.

    // Now all the players are connected to the server
    // We can start the main game loop
    while (gameRunning == true) {

        HandlePlayersWhoDroppedOut ();

        if (PlayersLeftGame () == true) {
            DisconnectAllPlayers ();
            Debug.LogError ("Player's left match, returning from thread");
            return;
        } else {
            foreach (NetworkPlayer p in participants) {

                try {
                    p.HandleTcpMessages ();
                    p.HandleUdpMessages ();
                } catch (IOException e) {
                    droppedPlayers.Add (p);
                }
            }

            try {
                RespawnRocksIfDestroyed ();
            } catch (System.IO.IOException e) {
                DisconnectAllPlayers ();
                return;
                Debug.LogError ("Failed to spawn rocks");
            }
        }
    }

1 Ответ

0 голосов
/ 13 июня 2018

Итак, я выяснил проблему с моим кодом.Я читал ровно одно сообщение udp в каждой итерации функции обработчика сообщений udp.Я изменил свою функцию, чтобы читать ВСЕ доступные сообщения udp в буфере, и отставание уменьшилось на 80%.Сообщения UDP встают в очередь в буфере быстрее, чем повторяется функция обработчика сообщений, поэтому проблема возникла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...