PUN 2 Lagkompensasjon

I Photon Network gjøres spillersynkronisering ved å sende verdier over nettverket i form av pakker.

For å synkronisere spillerposisjonen må vi for eksempel sende Vector3 for posisjon og Quaternion for rotasjon, og når verdiene er mottatt, bruker vi dem for å transformere.

Men siden verdiene sendes i intervaller, vil bare å bruke dem til å transformere resultere i en hakkete bevegelse, det er der Vector3.Lerp og Quaternion.Lerp kommer på plass.

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

Men selv denne metoden har noen ulemper: bare å jevne ut posisjon og rotasjon vil resultere i en unøyaktig representasjon av spillerens bevegelse, noe som ikke er helt egnet for noen typer spill, hvor presisjon er viktig.

Nedenfor er en forbedret versjon av posisjonssynkronisering, som tar hensyn til nettverkstid og prøver å gjenskape den opprinnelige bevegelsen så tett som mulig:

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));
        }
    }
}
  • Fest skriptet ovenfor til din spillerforekomst og tilordne det til PhotonView Observed Components.