Компенсація відставання 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.