Bù độ trễ PUN 2

Trong Photon Network, việc đồng bộ hóa trình phát được thực hiện bằng cách gửi các giá trị qua mạng dưới dạng gói.

Ví dụ: để đồng bộ hóa vị trí của người chơi, chúng ta cần gửi Vector3 cho vị trí và Quaternion để xoay, sau đó khi nhận được các giá trị, chúng ta áp dụng chúng để chuyển đổi.

Tuy nhiên, vì các giá trị được gửi theo từng khoảng thời gian nên chỉ cần áp dụng chúng để biến đổi sẽ dẫn đến chuyển động giật cục, đó là lúc Vector3.Lerp và Quaternion.Lerp xuất hiện.

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

Nhưng ngay cả phương pháp này cũng có một số nhược điểm: chỉ cần làm mịn vị trí và xoay sẽ dẫn đến việc thể hiện không chính xác chuyển động của người chơi, điều này không hoàn toàn phù hợp với một số loại trò chơi trong đó độ chính xác là quan trọng.

Dưới đây là phiên bản cải tiến của đồng bộ hóa vị trí, có tính đến thời gian kết nối mạng và cố gắng tái tạo chuyển động ban đầu càng sát càng tốt:

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));
        }
    }
}
  • Đính kèm tập lệnh ở trên vào phiên bản Trình phát của bạn và gán nó cho các Thành phần được quan sát của PhotonView.