Synchroniseer starre lichamen via netwerk met PUN 2

Het synchroniseren van objecten in PUN 2 is eenvoudig, maar hoe zit het met het synchroniseren van Rigidbodies?

In tegenstelling tot gewone GameObjects wordt Rigidbody ook beïnvloed door zwaartekracht (zo niet kinematisch) en andere objecten. Dus in plaats van alleen de transformatie van het object te synchroniseren, moeten we ook een aantal extra parameters synchroniseren, zoals velocity en angularVelocity.

In dit bericht laat ik zien hoe je interactieve Rigidbodies kunt maken die door elke speler in de kamer kunnen worden beïnvloed en via het netwerk kunnen worden gesynchroniseerd.

Unity versie gebruikt in deze tutorial: Unity 2018.3.0f2 (64-bit)

Deel 1: PUN 2 en multiplayer-voorbeeld instellen

We hebben al een tutorial over hoe je een multiplayer-voorbeeld kunt opzetten met PUN 2, bekijk de onderstaande link:

Maak een multiplayergame in Unity 3D met PUN 2

Kom terug zodra je klaar bent met het opzetten van een multiplayerproject, zodat we verder kunnen gaan.

U kunt ook tijd besparen door het bronproject hier op te halen.

Deel 2: Interactieve starre lichamen toevoegen

Als je de bovenstaande tutorial zou volgen, zou je nu 2 scènes hebben "GameLobby" en "GameLevel"

  • Open de scène "GameLevel" en maak een paar kubussen (GameObject -> 3D-object -> Kubus)

  • Voeg een Rigidbody-component toe aan elke kubus
  • Voeg een PhotonView-component toe aan elke kubus

Nu moeten we een nieuw script maken dat de Rigidbodies via het netwerk synchroniseert.

  • Maak een nieuw script en noem het 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);
            }
        }
    }
}
  • Koppel PUN2_RigidbodySync aan beide kubussen en wijs deze ook toe aan Photon View "Observed Components":

We moeten ook enkele wijzigingen aanbrengen in het PUN2_PlayerSync-script uit de multiplayer-tutorial:

  • Open PUN2_PlayerSync.cs
  • In void Start(), voeg binnen if(photonView.IsMine) deze code toe:
            //Player is local
            gameObject.tag = "Player";
            //Add Rigidbody to make the player interact with rigidbody
            Rigidbody r = gameObject.AddComponent<Rigidbody>();
            r.isKinematic = true;

Dus nu zou void Start() er zo uit moeten zien:

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

Door een component Rigidbody toe te voegen, zorgen we ervoor dat de spelerinstantie kan communiceren met andere Rigidbodies en door de tag te wijzigen in "Player" kunnen we detecteren of het een lokale instantie was die in botsing kwam met een stijf lichaam.

  • Sla de GameLevel-scène op nadat alles klaar is.

Laten we nu een build maken en testen!

Sharp Coder Video speler

Alles werkt zoals verwacht, nu kunnen Rigidbodies via het netwerk worden gesynchroniseerd terwijl ze nog steeds interactief zijn.

Voorgestelde artikelen
Maak een multiplayergame in Unity met PUN 2
Maak een multiplayer-autospel met PUN 2
PUN 2 vertragingscompensatie
Unity voegt multiplayer-chat toe aan de PUN 2-kamers
Photon Network (klassiek) beginnershandleiding
Samen multiplayer-netwerkgames bouwen
Multiplayer-datacompressie en bitmanipulatie