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));
        }
    }
}
  • أرفق البرنامج النصي أعلاه بمثيل المشغل الخاص بك وقم بتعيينه إلى PhotonView Observed Components.