Synchronisieren Sie Rigidbodies über das Netzwerk mit PUN 2
Das Synchronisieren von Objekten in PUN 2 ist einfach, aber wie sieht es mit der Synchronisierung von Rigidbodies aus?
Im Gegensatz zu normalen GameObjects wird Rigidbody auch von der Schwerkraft (wenn nicht kinematisch) und anderen Objekten beeinflusst. Anstatt also nur die Transformation des Objekts zu synchronisieren, müssen wir auch einige zusätzliche Parameter synchronisieren, wie zum Beispiel velocity und angularVelocity.
In diesem Beitrag werde ich zeigen, wie man interaktive Rigidbodies erstellt, die von jedem Spieler im Raum beeinflusst und über das Netzwerk synchronisiert werden können.
Unity In diesem Tutorial verwendete Version: Unity 2018.3.0f2 (64-Bit)
Teil 1: Einrichten von PUN 2 und Multiplayer-Beispiel
Wir haben bereits ein Tutorial zum Einrichten eines Multiplayer-Beispiels mit PUN 2, schauen Sie sich den Link unten an:
Erstellen Sie ein Multiplayer-Spiel in Unity 3D mit PUN 2
Kommen Sie zurück, sobald Sie mit der Einrichtung eines Multiplayer-Projekts fertig sind, damit wir fortfahren können.
Alternativ können Sie Zeit sparen, indem Sie das Quellprojekt von hier herunterladen.
Teil 2: Hinzufügen interaktiver starrer Körper
Wenn Sie dem obigen Tutorial gefolgt wären, hätten Sie jetzt 2 Szenen "GameLobby" und "GameLevel"
- Öffnen Sie die "GameLevel"-Szene und erstellen Sie ein paar Würfel (GameObject -> 3D-Objekt -> Würfel).
- Fügen Sie jedem Würfel eine Rigidbody-Komponente hinzu
- Fügen Sie jedem Cube eine PhotonView-Komponente hinzu
Jetzt müssen wir ein neues Skript erstellen, das die Rigidbodies über das Netzwerk synchronisiert.
- Erstellen Sie ein neues Skript und nennen Sie es 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);
}
}
}
}
- Hängen Sie PUN2_RigidbodySync an beide Cubes an und weisen Sie es auch Photon View "Observed Components" zu:
Wir müssen auch einige Änderungen am PUN2_PlayerSync-Skript aus dem Multiplayer-Tutorial vornehmen:
- Öffnen Sie PUN2_PlayerSync.cs
- Fügen Sie in void Start() innerhalb von if(photonView.IsMine) diesen Code hinzu:
//Player is local
gameObject.tag = "Player";
//Add Rigidbody to make the player interact with rigidbody
Rigidbody r = gameObject.AddComponent<Rigidbody>();
r.isKinematic = true;
Nun sollte void Start() also so aussehen:
// 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);
}
}
}
Durch das Hinzufügen einer Rigidbody-Komponente stellen wir sicher, dass die Player-Instanz mit anderen Rigidbodies interagieren kann und indem wir das Tag in "Player" ändern, können wir erkennen, ob es eine lokale Instanz war, die mit einem Rigidbody kollidierte.
- Speichern Sie die GameLevel-Szene, nachdem alles erledigt ist.
Jetzt erstellen wir einen Build und testen ihn!
Alles funktioniert wie erwartet, jetzt können Rigidbodies über das Netzwerk synchronisiert werden und sind dennoch interaktiv.