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!
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.