Синхронізація жорстких тіл через мережу за допомогою PUN 2

Синхронізація об’єктів у PUN 2 проста, але як щодо синхронізації твердих тіл?

На відміну від звичайних ігрових об’єктів, на Rigidbody також впливає гравітація (якщо не кінематика) та інші об’єкти. Тож замість того, щоб синхронізувати лише Transform об’єкта, нам також потрібно синхронізувати кілька додаткових параметрів, таких як velocity і angularVelocity.

У цьому дописі я покажу, як створити інтерактивні жорсткі тіла, на які може впливати кожен гравець у кімнаті та синхронізувати їх через мережу.

Unity версія, використана в цьому підручнику: Unity 2018.3.0f2 (64-розрядна)

Частина 1: Налаштування PUN 2 і приклад багатокористувацької гри

У нас уже є підручник про те, як налаштувати приклад багатокористувацької гри за допомогою PUN 2, перегляньте посилання нижче:

Створіть багатокористувацьку гру в Unity 3D за допомогою PUN 2

Поверніться, коли завершите налаштування проекту для кількох гравців, щоб ми могли продовжити.

Крім того, ви можете заощадити час, отримавши вихідний проект з тут.

Частина 2: Додавання інтерактивних жорстких тіл

Якщо ви дотримувалися підручника вище, у вас тепер буде 2 сцени "GameLobby" і "GameLevel"

  • Відкрийте сцену "GameLevel" і створіть пару кубів (GameObject -> 3D Object -> Cube)

  • Додайте компонент Rigidbody до кожного куба
  • Додайте компонент PhotonView до кожного куба

Тепер нам потрібно створити новий сценарій, який синхронізуватиме Rigidbodies через мережу.

  • Створіть новий сценарій і назвіть його 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);
            }
        }
    }
}
  • Прикріпіть PUN2_RigidbodySync до обох кубів, а також призначте його Photon View "Observed Components":

Нам також потрібно внести деякі зміни в сценарій PUN2_PlayerSync з посібника з багатокористувацької гри:

  • Відкрийте PUN2_PlayerSync.cs
  • У 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;

Тепер void Start() має виглядати так:

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

Додавши компонент Rigidbody, ми переконаємося, що екземпляр гравця може взаємодіяти з іншими Rigidbody, а змінивши тег на "Player", ми можемо визначити, чи локальний екземпляр зіткнувся з Rigidbody.

  • Збережіть сцену GameLevel після того, як усе буде зроблено.

Тепер створимо збірку та протестуємо її!

Sharp Coder Відеоплеєр

Усе працює, як очікувалося, тепер Rigidbodies можна синхронізувати через мережу, залишаючись взаємодіючими.

Рекомендовані статті
Створіть багатокористувацьку гру в Unity за допомогою PUN 2
Створіть багатокористувацьку автомобільну гру за допомогою PUN 2
Photon Network (Classic) Посібник для початківців
Компенсація відставання PUN 2
Unity Додавання чату для кількох гравців до кімнат PUN 2
Створення багатокористувацьких мережевих ігор в Unity
Багатокористувацьке стиснення даних і маніпулювання бітами