Компенсація відставання PUN 2

У Photon Network синхронізація програвача здійснюється шляхом надсилання значень через мережу у вигляді пакетів.

Наприклад, щоб синхронізувати позицію гравця, нам потрібно надіслати Vector3 для позиції та Quaternion для обертання, а потім, коли значення отримані, ми застосовуємо їх для перетворення.

Однак, оскільки значення надсилаються з інтервалами, просте застосування їх для перетворення призведе до ривчастого руху, ось тут і на місці Vector3.Lerp і Quaternion.Lerp.

transform.position = Vector3.Lerp(transform.position, latestPos, Time.deltaTime * 5);
transform.rotation = Quaternion.Lerp(transform.rotation, latestRot, Time.deltaTime * 5);

Але навіть у цього методу є деякі недоліки: просте згладжування позиції та обертання призведе до неточного представлення руху гравця, що не зовсім підходить для деяких типів ігор, де важлива точність.

Нижче наведено вдосконалену версію синхронізації позиції, яка враховує час роботи в мережі та намагається якомога точніше відтворити оригінальний рух:

using UnityEngine;
using Photon.Pun;

public class PUN2_LagFreePlayerSync : MonoBehaviourPun, IPunObservable
{
    //Values that will be synced over network
    Vector3 latestPos;
    Quaternion latestRot;
    //Lag compensation
    float currentTime = 0;
    double currentPacketTime = 0;
    double lastPacketTime = 0;
    Vector3 positionAtLastPacket = Vector3.zero;
    Quaternion rotationAtLastPacket = Quaternion.identity;

    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        if (stream.IsWriting)
        {
            //We own this player: send the others our data
            stream.SendNext(transform.position);
            stream.SendNext(transform.rotation);
        }
        else
        {
            //Network player, receive data
            latestPos = (Vector3)stream.ReceiveNext();
            latestRot = (Quaternion)stream.ReceiveNext();

            //Lag compensation
            currentTime = 0.0f;
            lastPacketTime = currentPacketTime;
            currentPacketTime = info.SentServerTime;
            positionAtLastPacket = transform.position;
            rotationAtLastPacket = transform.rotation;
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (!photonView.IsMine)
        {
            //Lag compensation
            double timeToReachGoal = currentPacketTime - lastPacketTime;
            currentTime += Time.deltaTime;

            //Update remote player
            transform.position = Vector3.Lerp(positionAtLastPacket, latestPos, (float)(currentTime / timeToReachGoal));
            transform.rotation = Quaternion.Lerp(rotationAtLastPacket, latestRot, (float)(currentTime / timeToReachGoal));
        }
    }
}
  • Прикріпіть наведений вище сценарій до свого екземпляра Player і призначте його спостережуваним компонентам PhotonView.
Рекомендовані статті
Створіть багатокористувацьку автомобільну гру за допомогою PUN 2
Unity Додавання чату для кількох гравців до кімнат PUN 2
Синхронізація жорстких тіл через мережу за допомогою PUN 2
Створіть багатокористувацьку гру в Unity за допомогою PUN 2
Photon Network (Classic) Посібник для початківців
Створення багатокористувацьких мережевих ігор в Unity
Багатокористувацьке стиснення даних і маніпулювання бітами