Sincronizar cuerpos rígidos a través de la red usando PUN 2
Sincronizar objetos en PUN 2 es simple, pero ¿qué pasa con la sincronización de Rigidbodies?
A diferencia de los GameObjects normales, Rigidbody también se ve afectado por Gravity (si no Kinematic) y otros objetos también. Entonces, en lugar de sincronizar solo la transformación del objeto, también necesitamos sincronizar un par de parámetros adicionales, como velocity y angularVelocity.
En esta publicación, mostraré cómo hacer Rigidbodies interactivos que pueden ser afectados por cada jugador en la sala y sincronizados a través de la red.
Unity versión utilizada en este tutorial: Unity 2018.3.0f2 (64 bits)
Parte 1: configuración de PUN 2 y ejemplo multijugador
Ya tenemos un tutorial sobre cómo configurar un ejemplo multijugador usando PUN 2, consulta el siguiente enlace:
Haz un juego multijugador en Unity 3D usando PUN 2
Vuelva una vez que haya terminado de configurar un proyecto multijugador para que podamos continuar.
Alternativamente, puede ahorrar tiempo obteniendo el proyecto de origen de aquí.
Parte 2: Adición de cuerpos rígidos interactivos
Si siguió el tutorial anterior, ahora tendría 2 escenas "GameLobby" y "GameLevel"
- Abra la escena "GameLevel" y cree un par de cubos (GameObject -> Objeto 3D -> Cubo)
- Agregue un componente Rigidbody a cada Cubo
- Agregue un componente PhotonView a cada cubo
Ahora necesitamos crear un nuevo Script que sincronizará los Rigidbodies a través de la red.
- Crea un nuevo Script y llámalo 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);
}
}
}
}
- Adjunte PUN2_RigidbodySync a ambos cubos y también asígnelo a Photon View "Observed Components":
También necesitamos hacer algunos cambios en el script PUN2_PlayerSync del tutorial multijugador:
- Abra PUN2_PlayerSync.cs
- En void Start(), dentro de if(photonView.IsMine) agrega este código:
//Player is local
gameObject.tag = "Player";
//Add Rigidbody to make the player interact with rigidbody
Rigidbody r = gameObject.AddComponent<Rigidbody>();
r.isKinematic = true;
Así que ahora void Start() debería verse así:
// 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);
}
}
}
Al agregar un componente Rigidbody, nos aseguramos de que la instancia del reproductor pueda interactuar con otros Rigidbodies y, al cambiar la etiqueta a "Player", podemos detectar si fue una instancia local que chocó con un Rigidbody.
- Guarde la escena GameLevel después de que todo haya terminado.
¡Ahora vamos a hacer una compilación y probarla!
Todo funciona como se esperaba, ahora Rigidbodies se puede sincronizar a través de la red sin dejar de ser interactuable.