Synchroniser les corps rigides sur le réseau à l'aide de PUN 2

La synchronisation d'objets dans PUN 2 est simple, mais qu'en est-il de la synchronisation de Rigidbodies ?

Contrairement aux GameObjects classiques, Rigidbody est également affecté par Gravity (sinon Kinematic) et d'autres objets également. Ainsi, au lieu de synchroniser uniquement la transformation de l'objet, nous devons également synchroniser quelques paramètres supplémentaires, tels que velocity et angularVelocity.

Dans cet article, je montrerai comment créer des Rigidbodies interactifs pouvant être affectés par tous les joueurs de la salle et synchronisés sur le réseau.

Unity version utilisée dans ce didacticiel: Unity 2018.3.0f2 (64 bits)

Partie 1: Configuration de PUN 2 et exemple multijoueur

Nous avons déjà un tutoriel sur la façon de configurer un exemple multijoueur en utilisant PUN 2, consultez le lien ci-dessous:

Créer un jeu multijoueur en Unity 3D en utilisant PUN 2

Revenez une fois que vous avez terminé de configurer un projet multijoueur afin que nous puissions continuer.

Vous pouvez également gagner du temps en récupérant le projet source depuis ici.

Partie 2: Ajouter des corps rigides interactifs

Si vous avez suivi le didacticiel ci-dessus, vous auriez maintenant 2 scènes "GameLobby" et "GameLevel"

  • Ouvrez la scène "GameLevel" et créez quelques cubes (GameObject -> Objet 3D -> Cube)

  • Ajouter un composant Rigidbody à chaque cube
  • Ajouter un composant PhotonView à chaque Cube

Nous devons maintenant créer un nouveau script qui synchronisera les Rigidbodies sur le réseau.

  • Créez un nouveau script et appelez-le 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);
            }
        }
    }
}
  • Attachez PUN2_RigidbodySync aux deux Cubes et attribuez-le également à Photon View "Observed Components":

Nous devons également apporter quelques modifications au script PUN2_PlayerSync du didacticiel multijoueur:

  • Ouvrez PUN2_PlayerSync.cs
  • Dans void Start(), à l'intérieur de if(photonView.IsMine) ajoutez ce code:
            //Player is local
            gameObject.tag = "Player";
            //Add Rigidbody to make the player interact with rigidbody
            Rigidbody r = gameObject.AddComponent<Rigidbody>();
            r.isKinematic = true;

Alors maintenant, void Start() devrait ressembler à ceci:

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

En ajoutant un composant Rigidbody, nous nous assurons que l'instance du lecteur peut interagir avec d'autres Rigidbodies et en changeant la balise en "Player" nous pouvons détecter s'il a été une instance locale qui est entrée en collision avec un Rigidbody.

  • Enregistrez la scène GameLevel une fois que tout est terminé.

Faisons maintenant un build et testons-le !

Sharp Coder Lecteur vidéo

Tout fonctionne comme prévu, maintenant les Rigidbodies peuvent être synchronisés sur le réseau tout en restant interactifs.

Articles suggérés
Créez un jeu multijoueur dans Unity en utilisant PUN 2
Créer des jeux multijoueurs en réseau dans Unity
Créez un jeu de voiture multijoueur avec PUN 2
Compensation de décalage PUN 2
Compression de données multijoueur et manipulation de bits
Unity ajoute un chat multijoueur aux salles PUN 2
Guide du débutant Photon Network (classique)