مزامنة الأجسام الصلبة عبر الشبكة باستخدام PUN 2

تعد مزامنة الكائنات في PUN 2 أمرًا بسيطًا، ولكن ماذا عن مزامنة الأجسام الصلبة؟

على عكس كائنات GameObjects العادية، يتأثر Rigidbody أيضًا بالجاذبية (إن لم يكن بالحركية) والكائنات الأخرى أيضًا. لذلك بدلاً من مزامنة تحويل الكائن فقط، نحتاج أيضًا إلى مزامنة بعض المعلمات الإضافية، مثل velocity و angularVelocity.

في هذا المنشور، سأوضح كيفية إنشاء أجسام صلبة تفاعلية يمكن أن تتأثر بكل لاعب في الغرفة وتتم مزامنتها عبر الشبكة.

Unity الإصدار المستخدم في هذا البرنامج التعليمي: Unity 2018.3.0f2 (64 بت)

الجزء 1: إعداد PUN 2 ومثال متعدد اللاعبين

لدينا بالفعل برنامج تعليمي حول كيفية إعداد مثال متعدد اللاعبين باستخدام PUN 2، تحقق من الرابط أدناه:

أنشئ لعبة متعددة اللاعبين في Unity 3D باستخدام PUN 2

عد بمجرد الانتهاء من إعداد مشروع متعدد اللاعبين حتى نتمكن من المتابعة.

وبدلاً من ذلك، يمكنك توفير الوقت عن طريق الحصول على المشروع المصدر من هنا.

الجزء 2: إضافة الأجسام الصلبة التفاعلية

إذا اتبعت البرنامج التعليمي أعلاه، فسيكون لديك الآن مشهدان "GameLobby" و "GameLevel"

  • افتح المشهد "GameLevel" وقم بإنشاء مكعبين (GameObject -> 3D Object -> Cube)

  • أضف مكون الجسم الصلب إلى كل مكعب
  • أضف مكون 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
  • في الفراغ 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;

لذا الآن يجب أن يبدو الفراغ 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، نتأكد من أن مثيل اللاعب يمكن أن يتفاعل مع Rigidbodys الأخرى وعن طريق تغيير العلامة إلى "Player" يمكننا اكتشاف ما إذا كان مثيلًا محليًا اصطدم بجسم Rigidbody.

  • احفظ مشهد GameLevel بعد الانتهاء من كل شيء.

الآن دعونا نبني ونختبره!

Sharp Coder مشغل فديوهات

كل شيء يعمل كما هو متوقع، الآن يمكن مزامنة Rigidbodies عبر الشبكة مع الاستمرار في التفاعل.