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ą!
Wszystko działa zgodnie z oczekiwaniami, teraz Rigidbodies można synchronizować przez sieć, zachowując jednocześnie interakcję.