Sincronizați corpuri rigide prin rețea folosind PUN 2

Sincronizarea obiectelor în PUN 2 este simplă, dar cum rămâne cu sincronizarea Rigidbodies?

Spre deosebire de GameObjects obișnuiți, Rigidbody este, de asemenea, afectat de Gravity (dacă nu Kinematic) și de alte obiecte. Deci, în loc să sincronizăm doar Transformarea obiectului, trebuie să sincronizăm și câțiva parametri suplimentari, cum ar fi velocity și angularVelocity.

În această postare, voi arăta cum să creez corpuri rigide interactive care pot fi afectate de fiecare jucător din cameră și sincronizate prin rețea.

Unity versiune folosită în acest tutorial: Unity 2018.3.0f2 (64 de biți)

Partea 1: Configurarea PUN 2 și Exemplu multiplayer

Avem deja un tutorial despre cum să configurați un exemplu de multiplayer folosind PUN 2, verificați linkul de mai jos:

Creați un joc multiplayer în Unity 3D folosind PUN 2

Reveniți după ce ați terminat de configurat un proiect multiplayer, astfel încât să putem continua.

Alternativ, puteți economisi timp obținând proiectul sursă de la aici.

Partea 2: Adăugarea de corpuri rigide interactive

Dacă ai urma tutorialul de mai sus ai avea acum 2 Scene "GameLobby" și "GameLevel"

  • Deschideți scena "GameLevel" și creați câteva cuburi (GameObject -> 3D Object -> Cube)

  • Adăugați o componentă Rigidbody la fiecare Cub
  • Adăugați o componentă PhotonView la fiecare Cub

Acum trebuie să creăm un nou Script care va sincroniza Rigidbodies prin rețea.

  • Creați un nou Script și numiți-l 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);
            }
        }
    }
}
  • Atașați PUN2_RigidbodySync la ambele cuburi și, de asemenea, atribuiți-l la Photon View "Observed Components":

De asemenea, trebuie să facem câteva modificări la scriptul PUN2_PlayerSync din tutorialul Multiplayer:

  • Deschideți PUN2_PlayerSync.cs
  • În void Start(), în interiorul if(photonView.IsMine) adăugați acest cod:
            //Player is local
            gameObject.tag = "Player";
            //Add Rigidbody to make the player interact with rigidbody
            Rigidbody r = gameObject.AddComponent<Rigidbody>();
            r.isKinematic = true;

Deci acum void Start() ar trebui să arate astfel:

    // 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);
            }
        }
    }

Adăugând o componentă Rigidbody ne asigurăm că instanța jucătorului poate interacționa cu alte Rigidbodies și prin schimbarea etichetei la "Player" putem detecta dacă a fost o instanță locală care s-a ciocnit cu un Rigidbody.

  • Salvați scena GameLevel după ce totul este terminat.

Acum să facem o construcție și să o testăm!

Sharp Coder Video player

Totul funcționează așa cum era de așteptat, acum Rigidbodies poate fi sincronizat prin rețea, fiind în același timp interacționabil.