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.