كيفية توجيه اطراف الشخصية اثناء الحركة في يونتي

unity

دائما تجد لكل لعبة شخصية خاصة بها تميزها عن غيرها, بل وحتى معروفه اكثر من اللعبه نفسها, ولكي يتحقق هذا لابد ان تكون الشخصيه فريدة فعلا, مثل مظهرها, صوتها, أو حتى طريقة تحركاتها.

 بالطبع كل هذه الجوانب ليست يسيرة التنفيذ بالطريقة الصحيح, لكن آخرهم وهو  التحركات، ان صُممت بطريقة خاطئة يمكن أن تلاحظه مدي سوئتها, مما يؤدي لإفساد تجربتك.

ولكن حتى مع تنفيذه باسلوب سليم, ففي أحيان كثيرة تجد مواقف معينة في اللعبة تتطلب تحركات خاصه جدا.
ما المشكلة إذا؟

يمكنك بسهولة أنشاء تحركات جديدة خاصة, بالطبع هذا حل صحيح ولكن ليس دائما, فإذا نظرت هنا لهذه المنطقة من لعبة Inside تلاحظ ان الشخصية حركت رأسها قليلا عندما وجدت حدثا مهما.

ولكن تظل تحركاتها الأساسية هي المشي المنخفض, وفي حالة مثل هذه فأنشاء حركات جديدة ليس أفضل حل, لما تكلفه من جهد ووقت, مع الوضع فى الاعتبار أن هذا الشيء الذي تطلب تغيير الحركة قد لا يكون نهائيا.

ماذا لو صنعت التحركات بالفعل لكن قررت بعد ذلك أن تغير الحدث نفسه ؟, وقتها تصبح بلا فائدة وتضطر لتحريكها من جديد.

ولكن يوجد حل آخر أكثر كفاءة بكثير وانسب لمثل هذه الحالات, وبالطبع هذا يوفر عليك الوقت والجهد وهو باستعمال القيود – Constraints في محرك الالعاب Unity.

تجهيز المشروع

هذه المرة تحتاج لتثبيت حزمة الـ Animation Rigging عن طريق Window >> Package Manager >> Animation Rigging.
وفي حالة لم تجده فما عليك سوي الضغط علي علامة الترس واختيار Advanced Project Settings  ثم تفعيل Enable Preview Packages, وبعدها يمكنك ايجاده في نافذة الـ Package Manager.

وبالنسبة لي فقد جهزت هذا المشهد مع تحميل هذه الشخصيه مع تحركاتها من Mixamo, وما اريد تنفيذه هو تعديل حركة رأس الشخصيه قليلا أثناء وجودها في مرمي بصر التوهج, وبعد ذلك ترجع للحاله الطبيعيه.

تجهيز هيكل الشخصية

لتنفيذ هذا تحتاج أولا تجهيز الهيكل الخاص بالشخصية, وهو ما يتطلب عدة خطوات
أولاها هي ان تضيف الـ Rig Builder على الشخصية وتحديدا على العنصر الذي يحمل مركبة المحرك – Animator.

وهذه المركبة هي المسؤولة عن السماح للهيكل بأن يُعدل بواسطة طبقات الريج – Rig Layers, ولكن ما هي هذه الطبقات وكيف يمكن اضافتها؟.

لاضافتها، أولا أضغط على زر الاضافة + وتراه يتطلب Rig والتي تمثل طبقات الريج, وتستطيع اضافة اكثر من واحده, ويمكنك تفعيل او تعطيل اي منها في أي وقت.

ولكن ما اضفته توا ليس الطبقه نفسها وانما خانة للطبقة, وما عليك الان سوى تحديد الطبقة التي تريد تعيينها.

والانشاء هذه الطبقة عليك اولا انشاء عنصر جديد فارغ بداخل الشخصية, ثم اضافة مركبة الريج – Rig.

وبداخلها يمكنك أن تجد متغيرات الوزن – Weight, وهو ما يعبر عن مدى تأثير هذه الطبقة علي تحركات الشخصيه, حيث 0 يبطل تأثيرها, و 1 يدل على أن تأثيرها كامل.

إضافة القيد

وهكذا يكون عملك مع الطبقه قد انتهى والان تبقى اضافة القيود التي تريدها مع تدريجها تحت هذا العنصر, حيث أن كل عنصر تضيفه كابن يحمل قيدا واحدا.

والقيد الذي نريد اضافته هنا هو  Multi-Aim Constraint, والذي يسمح بتوجيه إحدى العظام لهدف أو عدة اهداف محددة مسبقا.

وبعدها تجد به عدة خيارات وما يهم منها هو العنصر المقيد – Constrained Object, والذي تعيينه بالعظمة التي تريد توجيهها للهدف.

اول خيار وهو الوزن – Weight, وظيفته هي التحكم بمدى تأثير القيد نفسه حيث 1 يعني تأثيرا كاملا و 0 يلغي التأثير.

أما عناصر المصدر – Source Objects, والتي بداخلها يمكنك اضافة اي عدد من العناصر وتحديد مدى تأثير كل منها على العظمة التي يتم توجيهها وهو ما تعينه للهدف الذي تريد توجيه الرأس له.

ولتفادي مشكلة ان تلتف الرأس أو أي عظمه عامة بطريقة زائده عن اللزوم, فقط تلاعب بقيمة الحد الأقصى – Max Limit, والذي لن يسمح للعظمة بتخطي الزاوية التي تعينت له.

والعكس صحيح مع الحد الأدنى – Min Limit, والذي يحدد زاوية الالتفاف ان لا تقل عن قيمته.

وما يتحكم بالمحور الذي يوجه للهدف هو خيار محور الهدف – Aim Axis, ولكي تعرف المحاور الخاصة بالعظمة التي تريدها فقط قم بتحديدها أثناء تحديد الوضع المحلي – Local.

وفي هذه الحاله فان مقدمة الرأس في اتجاه محور الـ Z.

وفي هذه الحاله فان مقدمة الرأس في اتجاه محور الـ Z.

يمكنك الان ان ترى الفرق بين وجود وعدم القيد, ولكن لا نريد الرأس ان تتوجه دائما للهدف, وانما فقط عند وجودها في نطاقه, لهذا تحتاج انشاء شيفرة – Script يغيير قيمة الوزن عند الدخول في النطاق وعن الخروج منه.

التحكم بالوزن من الشيفرة – script

بداية, سأقوم بإنشاء شيفرة للاعب نفسه كي يتحكم بقيمة وزن القيد, بحيث انه بأضافة متغير من نوع بوولين – Boolean والتحقق من حالته, فإن كان مفعلا يضبط قيمة متغير الوزن الي 1, والعكس يعين قيمته الي 0.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// النطاق الخاص بحزمة الـ Animation Rigging.
using UnityEngine.Animations.Rigging;


public class HeadOrienting : MonoBehaviour
{
    public MultiAimConstraint Constraint;
// قيمة الوزن التي تتحكم بقيمة وزن للقيد
    private float weight;
// للتحكم بحالة الرأس
    public bool LookToTarget;
 
    void Update()
    {
// تعيين قيمة الوزن في القيد تساوي قيمة متغير الوزن
        Constraint.weight = weight;


        if(LookToTarget == true)
        {
            weight = 1;
        }else
        {
            weight = 0;
        }
    }


}

ولكن هذا يظهر حركة الرأس لحظيه وغير منطقية لهذا تحتاج لإضافة ما يزيد من سلاسة الانتقال.

ولأصلاح هذا نستعمل الاستيفاء الخطي – Lerp بجانب منحني حركة خاص – Animation Curve, حيث وظيفة الاستيفاء الخطي هي الانتقال من قيمة 0 الى 1 ولكن ان طبقنا هذا على وزن القيد, تصبح حركته خطية وهو ما لن تجده الا في الروبوتات, لكن باضافة منحنى الحركة يكون بمقدورك التحكم بكيفية الانتقال كما تريد.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations.Rigging;
public class HeadOrienting : MonoBehaviour
{
    public MultiAimConstraint Constraint;
    private float weight;
    public bool LookToTarget;
// التحكم بسرعة وقت منحنى الحركة 
    public float OrientingSpeed;
// العداد الخاص بمنحني الحركة
    private float curveTime;


// منحنيات الحركة التحكم بسرعة دوران الرأس
    public AnimationCurve LookCurve;
    public AnimationCurve IgnoreCurve;


    void Update()
    {
        Constraint.weight = weight;


        if(curveTime <1 && LookToTarget == true)
        {
// عند تحقق شرط تفعيل النظر للهدف و ان وقت المنحني اقل من 1 يزيد قيمته تدريجيا
            curveTime += OrientingSpeed * Time.deltaTime;
// يعين قيمة وزن القيد بمعادلة استيفاء الخطي من 0 الى 1 مع تعيين قيمة الزمن بمنحني الحركة 
            weight = Mathf.Lerp(0,1,LookCurve.Evaluate(curveTime));          
        }else if(curveTime > 0 && LookToTarget == false)
        {
// وعند تعطيل النظر للهدف وقيمة وقت المنحني أكبر من 0 تقل قيمته تدريجيا مع تعيين قيمة وزن القيد ليساوي الاستيفاء الخطي من 0 الى 1 أيضا وقيمة زمنه هي وقت منحنى الحركة
            curveTime -= OrientingSpeed * Time.deltaTime;
            weight = Mathf.Lerp(0,1,IgnoreCurve.Evaluate(curveTime));
        }
    }
}

إضافة منطقة التفعيل

والان تبقى وضع ما يفعل ويعطل النظر للهدف, ولهذا يمكن وضع عنصر فارغ في مكان النطاق واضافة مركبة Box Collider مع تفعيل Is Trigger, وبعدها انشاء شيفرة جديدة له.
ولاحظ أنه لابد من وجود وسم Player علي الشخصيه, بالاضافه لاحتوائه علي مركبات Collider و Rigid Body.

using UnityEngine;
public class ActivateArea : MonoBehaviour
{
    public HeadOrienting HeadOrienting;
    private void OnTriggerEnter(Collider other)
    {
// التحقق من أن ما دخل المنطقة يحمل وسم اللاعب
        if(other.CompareTag("Player"))
        {
// تفعيل النظر للهدف إذا تحقق الشرط
            other.GetComponent<HeadOrienting>().LookToTarget = true;
        }
    }
    private void OnTriggerExit(Collider other)
    {
// التحقق من أن ما غادر المنطقة يحمل اسم اللاعب
        if(other.CompareTag("Player"))
        {
// تعطيل النظر للهدف إذا تحقق الشرط
            other.GetComponent<HeadOrienting>().LookToTarget = false;
        }
    }
}

وبهذا تصبح شخصيتك في اللعبة أكثر واقعية، من خلال سلوكها المتسق مع البيئة حولها, وتفاعلها المناسب مع الأحداث المحيطة بها تلقائيا, مما يؤدي الي تجربه اكثر اندماجا في اللعبة.

وتذكر أن أهم ميزة لهذه الطريقة من العمل هي توفير جهد وعناء كبيرين عليك, فلن تحتاج بعد الآن إلى تحريك شخصيتك بطريقة مخصصه لكل ما في اللعبة, مما يُتيح لك التركيز على جوانب أخرى أهم.

0 0 votes
Article Rating
Subscribe
نبّهني عن
guest

0 تعليقات
Inline Feedbacks
View all comments