Синхронізація жорстких тіл через мережу за допомогою 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 після того, як усе буде зроблено.
Тепер створимо збірку та протестуємо її!
Усе працює, як очікувалося, тепер Rigidbodies можна синхронізувати через мережу, залишаючись взаємодіючими.