Synkronisera stela kroppar över nätverk med PUN 2

Att synkronisera objekt i PUN 2 är enkelt, men hur är det med att synkronisera Rigidbodies?

Till skillnad från vanliga GameObjects, påverkas Rigidbody också av Gravity (om inte Kinematic) och andra objekt också. Så istället för att bara synkronisera objektets Transform, måste vi också synkronisera ett par ytterligare parametrar, såsom hastighet och vinkelhastighet.

I det här inlägget kommer jag att visa hur man gör interaktiva Rigidbodies som kan påverkas av varje spelare i rummet och synkroniseras över nätverket.

Unity version som används i denna handledning: Unity 2018.3.0f2 (64-bitars)

Del 1: Ställa in PUN 2 och Multiplayer Exempel

Vi har redan en handledning om hur man ställer in ett multiplayer-exempel med PUN 2, kolla länken nedan:

Gör ett spel för flera spelare i Unity 3D med PUN 2

Kom tillbaka när du är klar med att skapa ett flerspelarprojekt så att vi kan fortsätta.

Alternativt kan du spara tid genom att hämta källprojektet här.

Del 2: Lägga till interaktiva stela kroppar

Om du följde handledningen ovan skulle du nu ha 2 scener "GameLobby" och "GameLevel"

  • Öppna "GameLevel"-scenen och skapa ett par kuber (GameObject -> 3D Object -> Cube)

  • Lägg till en Rigidbody-komponent till varje kub
  • Lägg till en PhotonView-komponent till varje kub

Nu måste vi skapa ett nytt skript som kommer att synkronisera Rigidbodies över nätverket.

  • Skapa ett nytt skript och kalla det PUN2_RigidbodySync

PUN2_RigidbodySync.cs

using UnityEngine;
using Photon.Pun;

public class PUN2_RigidbodySync : MonoBehaviourPun, IPunObservable
{

    Rigidbody r;

    Vector3 latestPos;
    Quaternion latestRot;
    Vector3 velocity;
    Vector3 angularVelocity;

    bool valuesReceived = false;

    // Start is called before the first frame update
    void Start()
    {
        r = GetComponent<Rigidbody>();
    }

    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);
            stream.SendNext(r.velocity);
            stream.SendNext(r.angularVelocity);
        }
        else
        {
            //Network player, receive data
            latestPos = (Vector3)stream.ReceiveNext();
            latestRot = (Quaternion)stream.ReceiveNext();
            velocity = (Vector3)stream.ReceiveNext();
            angularVelocity = (Vector3)stream.ReceiveNext();

            valuesReceived = true;
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (!photonView.IsMine && valuesReceived)
        {
            //Update Object position and Rigidbody parameters
            transform.position = Vector3.Lerp(transform.position, latestPos, Time.deltaTime * 5);
            transform.rotation = Quaternion.Lerp(transform.rotation, latestRot, Time.deltaTime * 5);
            r.velocity = velocity;
            r.angularVelocity = angularVelocity;
        }
    }

    void OnCollisionEnter(Collision contact)
    {
        if (!photonView.IsMine)
        {
            Transform collisionObjectRoot = contact.transform.root;
            if (collisionObjectRoot.CompareTag("Player"))
            {
                //Transfer PhotonView of Rigidbody to our local player
                photonView.TransferOwnership(PhotonNetwork.LocalPlayer);
            }
        }
    }
}
  • Fäst PUN2_RigidbodySync till båda kuberna och tilldela den även till Photon View "Observed Components":

Vi måste också göra några ändringar i PUN2_PlayerSync-skriptet från Multiplayer-handledningen:

  • Öppna PUN2_PlayerSync.cs
  • In void Start(), inuti if(photonView.IsMine) lägg till denna kod:
            //Player is local
            gameObject.tag = "Player";
            //Add Rigidbody to make the player interact with rigidbody
            Rigidbody r = gameObject.AddComponent<Rigidbody>();
            r.isKinematic = true;

Så nu ska void Start() se ut så här:

    // Use this for initialization
    void Start()
    {
        if (photonView.IsMine)
        {
            //Player is local
            gameObject.tag = "Player";
            //Add Rigidbody to make the player interact with rigidbody
            Rigidbody r = gameObject.AddComponent<Rigidbody>();
            r.isKinematic = true;
        }
        else
        {
            //Player is Remote, deactivate the scripts and object that should only be enabled for the local player
            for (int i = 0; i < localScripts.Length; i++)
            {
                localScripts[i].enabled = false;
            }
            for (int i = 0; i < localObjects.Length; i++)
            {
                localObjects[i].SetActive(false);
            }
        }
    }

Genom att lägga till en Rigidbody-komponent ser vi till att spelarinstansen kan interagera med andra Rigidbodies och genom att ändra taggen till "Player" kan vi upptäcka om det var en lokal instans som kolliderade med en Rigidbody.

  • Spara GameLevel-scenen när allt är klart.

Låt oss nu bygga och testa den!

Sharp Coder Videospelare

Allt fungerar som förväntat, nu kan Rigidbodies synkroniseras över nätverk samtidigt som de är interagerbara.

Föreslagna artiklar
Skapa ett multiplayer-spel i Unity med PUN 2
Gör ett bilspel för flera spelare med PUN 2
Bygga nätverksspel för flera spelare i Unity
PUN 2 fördröjningskompensation
Unity Lägger till flerspelarchatt till PUN 2-rummen
Photon Network (Classic) Nybörjarguide
Multiplayer-datakomprimering och bitmanipulation