Synkroniser rigidbodies over netværk ved hjælp af PUN 2

Synkronisering af objekter i PUN 2 er enkelt, men hvad med at synkronisere Rigidbodies?

I modsætning til almindelige GameObjects, påvirkes Rigidbody også af Gravity (hvis ikke kinematisk) og andre objekter. Så i stedet for kun at synkronisere objektets Transform, skal vi også synkronisere et par ekstra parametre, såsom velocity og angularVelocity.

I dette indlæg vil jeg vise, hvordan man laver interaktive Rigidbodies, der kan påvirkes af hver spiller i rummet og synkroniseres over netværket.

Unity version brugt i denne øvelse: Unity 2018.3.0f2 (64-bit)

Del 1: Opsætning af PUN 2 og multiplayer eksempel

Vi har allerede en tutorial om, hvordan man opsætter et multiplayer-eksempel ved hjælp af PUN 2, tjek linket nedenfor:

Lav et multiplayer-spil i Unity 3D ved hjælp af PUN 2

Vend tilbage, når du er færdig med at oprette et multiplayer-projekt, så vi kan fortsætte.

Alternativt kan du spare tid ved at hente kildeprojektet fra her.

Del 2: Tilføjelse af interaktive rigidbodies

Hvis du fulgte vejledningen ovenfor, ville du nu have 2 scener "GameLobby" og "GameLevel"

  • Åbn "GameLevel"-scenen, og lav et par kuber (GameObject -> 3D-objekt -> Cube)

  • Tilføj en Rigidbody-komponent til hver terning
  • Tilføj en PhotonView-komponent til hver terning

Nu skal vi oprette et nyt script, der vil synkronisere Rigidbodies over netværket.

  • Opret et nyt script og kald det 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);
            }
        }
    }
}
  • Vedhæft PUN2_RigidbodySync til begge terninger, og tildel den også til Photon View "Observed Components":

Vi skal også lave nogle ændringer til PUN2_PlayerSync-scriptet fra Multiplayer-vejledningen:

  • Åbn PUN2_PlayerSync.cs
  • In void Start(), inde i if(photonView.IsMine) tilføj denne kode:
            //Player is local
            gameObject.tag = "Player";
            //Add Rigidbody to make the player interact with rigidbody
            Rigidbody r = gameObject.AddComponent<Rigidbody>();
            r.isKinematic = true;

Så nu skulle void Start() se sådan ud:

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

Ved at tilføje en Rigidbody-komponent sikrer vi, at spillerinstansen kan interagere med andre Rigidbodies, og ved at ændre tagget til "Player" kan vi opdage, om det var en lokal instans, der kolliderede med en Rigidbody.

  • Gem GameLevel-scenen, når alt er færdigt.

Lad os nu lave en build og teste den!

Sharp Coder Videoafspiller

Alt fungerer som forventet, nu kan Rigidbodies synkroniseres over netværket, mens de stadig kan interageres.

Foreslåede artikler
Lav et multiplayer-spil i Unity ved hjælp af PUN 2
Lav et multiplayer bilspil med PUN 2
Unity tilføjer multiplayer-chat til PUN 2-rummene
Multiplayer datakomprimering og bitmanipulation
PUN 2 Lagkompensation
Unity Login System med PHP og MySQL
Photon Network (klassisk) begyndervejledning