PUN 2 ラグ補正

Photon Network では、プレーヤーの同期は、パケットの形式でネットワーク上に値を送信することによって行われます。

たとえば、プレーヤーの位置を同期するには、位置については Vector3 を、回転についてはクォータニオンを送信する必要があります。その後、値を受信したら、それらの値を変換に適用します。

ただし、値は一定間隔で送信されるため、単純に変換に適用すると動きが途切れ途切れになってしまいます。そこで、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 Observed Components に割り当てます。
おすすめの記事
PUN 2 を使用してマルチプレイヤー車ゲームを作成する
Unity が PUN 2 ルームにマルチプレイヤー チャットを追加
PUN 2 を使用してネットワーク上でリジッドボディを同期する
PUN 2 を使用して Unity でマルチプレイヤー ゲームを作成する
Unity でマルチプレイヤー ネットワーク ゲームを構築する
マルチプレイヤーのデータ圧縮とビット操作
Unity オンライン リーダーボードのチュートリアル