Synchronizuj sztywne ciała przez sieć za pomocą PUN 2

Synchronizowanie obiektów w PUN 2 jest proste, ale co z synchronizacją Rigidbodies?

W przeciwieństwie do zwykłych obiektów GameObject, Rigidbody podlega także wpływowi Grawitacji (jeśli nie Kinematyki) i innym obiektom. Zamiast więc synchronizować tylko transformację obiektu, musimy także zsynchronizować kilka dodatkowych parametrów, takich jak velocity i angularVelocity.

W tym poście pokażę, jak stworzyć interaktywne Rigidbody, na które może mieć wpływ każdy gracz w pokoju i zsynchronizować je przez sieć.

Unity wersja używana w tym samouczku: Unity 2018.3.0f2 (64-bitowa)

Część 1: Konfiguracja PUN 2 i przykład gry wieloosobowej

Mamy już samouczek dotyczący konfiguracji przykładowego trybu wieloosobowego przy użyciu PUN 2, sprawdź poniższy link:

Stwórz grę wieloosobową w Unity 3D, używając PUN 2

Wróć, gdy skończysz konfigurować projekt dla wielu graczy, abyśmy mogli kontynuować.

Alternatywnie możesz zaoszczędzić czas, pobierając projekt źródłowy z tutaj.

Część 2: Dodawanie interaktywnych brył sztywnych

Jeśli postępowałeś zgodnie z powyższym samouczkiem, miałbyś teraz 2 sceny "GameLobby" i "GameLevel"

  • Otwórz scenę "GameLevel" i utwórz kilka kostek (GameObject -> Obiekt 3D -> Kostka)

  • Dodaj komponent Rigidbody do każdej kostki
  • Dodaj komponent PhotonView do każdej kostki

Teraz musimy utworzyć nowy skrypt, który zsynchronizuje Rigidbodies przez sieć.

  • Utwórz nowy skrypt i nadaj mu nazwę 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);
            }
        }
    }
}
  • Dołącz PUN2_RigidbodySync do obu kostek, a także przypisz go do Photon View "Observed Components":

Musimy także wprowadzić pewne zmiany w skrypcie PUN2_PlayerSync z samouczka gry wieloosobowej:

  • Otwórz plik PUN2_PlayerSync.cs
  • W void Start(), wewnątrz if(photonView.IsMine) dodaj ten kod:
            //Player is local
            gameObject.tag = "Player";
            //Add Rigidbody to make the player interact with rigidbody
            Rigidbody r = gameObject.AddComponent<Rigidbody>();
            r.isKinematic = true;

Zatem teraz void Start() powinna wyglądać tak:

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

Dodając komponent Rigidbody, upewniamy się, że instancja gracza może wchodzić w interakcję z innymi Rigidbodies, a zmieniając znacznik na "Player" możemy wykryć, czy była to instancja lokalna, która zderzyła się z Rigidbody.

  • Po zakończeniu wszystkiego zapisz scenę GameLevel.

Teraz zróbmy kompilację i przetestujmy ją!

Sharp Coder Odtwarzacz wideo

Wszystko działa zgodnie z oczekiwaniami, teraz Rigidbodies można synchronizować przez sieć, zachowując jednocześnie interakcję.

Sugerowane artykuły
Stwórz grę wieloosobową w Unity, używając PUN 2
Stwórz wieloosobową grę samochodową w PUN 2
Przewodnik dla początkujących sieci Photon (klasyczny).
Kompensacja opóźnienia PUN 2
Unity Dodanie czatu wieloosobowego do pokoi PUN 2
Kompresja danych i manipulacja bitami w trybie wieloosobowym
Samouczek dotyczący tablicy liderów Unity Online