PUN 2 Verzögerungskompensation
In Photon Network erfolgt die Player-Synchronisierung durch das Senden von Werten über das Netzwerk in Form von Paketen.
Um beispielsweise die Spielerposition zu synchronisieren, müssen wir Vector3 für die Position und Quaternion für die Rotation senden. Wenn die Werte dann empfangen werden, wenden wir sie zur Transformation an.
Da die Werte jedoch in Intervallen gesendet werden, führt die einfache Anwendung auf die Transformation zu einer abgehackten Bewegung. Hier kommen Vector3.Lerp und Quaternion.Lerp ins Spiel.
transform.position = Vector3.Lerp(transform.position, latestPos, Time.deltaTime * 5);
transform.rotation = Quaternion.Lerp(transform.rotation, latestRot, Time.deltaTime * 5);
Aber auch diese Methode hat einige Nachteile: Das bloße Glätten von Position und Drehung führt zu einer ungenauen Darstellung der Bewegung des Spielers, was für einige Arten von Spielen, bei denen es auf Präzision ankommt, nicht ganz geeignet ist.
Nachfolgend finden Sie eine verbesserte Version der Positionssynchronisierung, die die Netzwerkzeit berücksichtigt und versucht, die ursprüngliche Bewegung so genau wie möglich nachzubilden:
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));
}
}
}
- Hängen Sie das obige Skript an Ihre Player-Instanz an und weisen Sie es PhotonView Observed Components zu.