#1 تاثير كشف التسلل من لعبة Assassin’s Creed Unity

unity

سلسلة العاب اساسنز كريد “Assassin’s Creed” تعتبر أحد أشهر العناوين عند الحديث عن تصنيف التخفي, والتي تميزت عن غيرها من الألعاب بتقديمها لحقبات زمنية مختلفة, وشخصيات تاريخية حقيقة, وطرق لعب جديدة, لتخدم أكثر شيء يميزها, والذي يمكنك معرفته من اسمها وهو الاغتيال.

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

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

فكرة العمل

تنقسم الفكرة هذه المرة لشيئان أساسيان :

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

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

ستبدأ اولا بتجهيز مشروع يونِتي بتغيير نظام الرسومات فيه, لتصبح قادرا على استعمال محرر الشيدر.
من خلال قائمة Window >> Package Manager >> Universal RP ثم تقوم بتثبيته في مشروعك.

ستقوم بعدها بعمل URP Asset، وهو عبارة عن ملف للتحكم باعدادات نظام الرسومات الجديد، ويمكنك إيجاده من خلال قائمة الإظهار – Rendering في نافذة المشروع ثم اختيار URP Asset with Universal Renderer ، ثم تأكد من تفعيل نسيج البعد – Depth Texture ونسيج العتامه – Opaque Texture والـ HDR فيه.

بعد هذا تقوم بتطبيق المعالجة النهائية – Post Process, عن طريق الذهاب الى نافذة الـ Hierarchy, واضافة Global Volume من خلال قائمة النطاق – Volume, ومن نافذة المشروع تقوم بعمل Volume Profile.

بعد هذا تقوم بإضافة تاثير الوهج – Bloom, والـ Vignette, الى الـ Volume Profile.
ويمكنك اضافة اي تاثير اخر تريده.
ثم تقوم بتفعيل المعالجة النهائية – Post Process في الكاميرا.

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

بدء العمل

ستحتاج أولا لانشاء نص برمجي عن طريقة قائمة Create واختيار C# Script, ثم تقوم بالحاقة بشخصية اللاعب نفسه, بحيث يكون مسئولا عن توليد النموذج الفراغي.

في البداية تقوم بعمل متغير من نوع مظهِر منَمذَج عظمي – SkinnedMeshRenderer, والذي يكون مسئولا عن الوصول إلى شكل المنَمذَج الذي يتم التحكم به بواسطة العظام, ومن ثم في دالة البدء – Start تقوم بكتابة ما يكون مسئولا عن إلحاق المكون الخاص بمظهِر المنَمذَج العظمي في المتغير الخاص بها.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Appearing : MonoBehaviour
{
  public SkinnedMeshRenderer SMR;

  void Start()
    {
      if(SMR == null ){
      SMR =  GetComponentInChildren<SkinnedMeshRenderer>();
      }
    }

توليد النموذج الفراغي

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

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

void Update()
  {       
    if(Input.GetKeyDown(KeyCode.Space){ 
    GenerateBSobject();
    }
  }

public void GenerateBSobject(){
  // إنشاء المنَمذَج نفسه لكنه فارغ ولا يحتوي الا على مكون  المحولات
  GameObject Obj = new GameObject();           
  // تعيين معلومات احداثيات المنَمذَج الذي تم توليده
  Obj.transform.SetPositionAndRotation(trans; form.position,transform.rotation);
  }

الان يمكنك تجربته, وستجد انه كلما ضغطت زر المسافة, فإن هناك منَمذَجا جديدا يظهر  في نافذة التسلسل Hierarchy, ولكنه يحمل فقط مكون  المحولات-Transform.

إظهار النموذج الفراغي

الان حان دور إلحاق المكون  الخاص باعطائه مظهرا يمكن رؤيته, وهما شكل المنَمذَج – Mesh Filter, المسئول عن تحديد الشكل نفسه, ومظهِر المنَمذَج – Mesh Renderer, المسئول عن جعل هذا الشكل ظاهرا.

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

public void GenerateBSobject(){
  // إنشاء المنَمذَج نفسه لكنه فارغ ولا يحتوي الا مكون  المحولات
  GameObject Obj = new GameObject()           
  // تعيين معلومات احداثيات المنَمذَج الذي تم توليده
  Obj.transform.SetPositionAndRotation(trans; form.position,transform.rotation);
  
  MeshRenderer MeshR = Obj.AddComponent<MeshRenderer>();
  MeshFilter MeshF = Obj.AddComponent<MeshFilter>();
    }

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

وسيكون هذا عن طريق امر تخزين بيانات المنَمذَج – BakeMesh الخاص بمظهِر المنَمذَج العظمي.
والذي يقوم بتسجيل مواقع جميع النقاط على المنَمذَج لحظة استعماله, وبعدها يقوم بتخزينها في المنَمذَج الذي يتم تحديده له.

 ولهذا تحتاج ان تقوم بإنشاء منَمذَج جديد, عن طريق الامر في السطر السابق له, وسيكون منَمذَجا فارغا بلا اي بيانات, ويمكن تخيله كانه حاوية, للشكل الذي يتم توليده.

الان تقوم بإلحاق المنَمذَج الجديد في الخانه الخاصه به في شكل المنَمذَج – Mesh Filter, ثم وضع الخامة التي سوف يستخدمها المنَمذَج في مظهِر المنَمذَج Mesh Renderer, ولكن لهذا تحتاج عمل متغير جديد من نوع Material, لتستطيع بعد ذلك اختيارها كما تشاء لاحقا من المحرر.

public SkinnedMeshRenderer SMR;
public Material BSMat;

public void GenerateBSobject(){
  // إنشاء المنَمذَج نفسه لكنه فارغ ولا يحتوي الا مكون المحولات  
  GameObject Obj = new GameObject()           
  // تعيين معلومات احداثيات المنَمذَج الذي تم توليده
  Obj.transform.SetPositionAndRotation(trans; form.position,transform.rotation);
  
  MeshRenderer MeshR = Obj.AddComponent<MeshRenderer>();
  MeshFilter MeshF = Obj.AddComponent<MeshFilter>();
  
  Mesh BSmesh = new Mesh();
  SMR.BakeMesh(BSmesh);
  
  //الأمر الخاص بإلحاق المنَمذَج في مكون شكل المنَمذَج - Mesh Filter
  MeshF.mesh = BSmesh;
  //الأمر الخاص بإلحاق الخامة في مكون مظهِر المنَمذَج - Mesh Renderer
  MeshR.material = BSMat;
  }

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

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

التحكم بمعدل التولد

اولا تحتاج لعمل متغير جديد من نوع رقم العشري – Float, ليكون خاصا بالفترة التي تكون بين تولد كل منَمذَج فراغي, وعمل متغير آخر مرتبط به من نفس النوع وسيكون هو العداد الخاص به.

 وطريقة عمله انه في البداية تقوم بتعيين قيمة متغير العداد لنفس قيمة المتغير الذي يكون متعلقا به, وفي هذه الحالة فهو متغير الـ AppearRate.

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

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

والان تبقى تدمير المنَمذَج الذي تم توليده, ولفعل هذا تقوم بإضافة أمر التدمير – Destroy في دالة GenerateBSobject, وبعدها اضافة الزمن الذي سيستغرقه المنَمذَج من لحظة إنشائها حتى تدميره.

 وفي حالتي جعلتها 5, ويمكنك تحويلها لمتغير عام, في حالة اردت ان تغيرها باستمرار من المحرك نفسه.

بعد ذلك عند تجربتك لها مرة اخرى, تجد أنه كلما زادت قيمة متغير AppearRate, كلما زادت المدة بين توليد المنَمذَجات.

public SkinnedMeshRenderer SMR;
public Material BSMat;

public float AppearRate = 2;
private float AppearRating;

void Update(){
  // تشغيل العداد
  if(AppearRating > 0 ){AppearRating -= Time.deltaTime;}
  
  if(Input.GetKeyDown(KeyCode.Space) && AppearRating <= 0){
    GenerateBSobject();}
  }

public void GenerateBSobject(){
  //إنشاء المنَمذَج نفسه لكنه فارغ ولا يحتوي الا مكون المحولات  
  GameObject Obj = new GameObject()           
  // تعيين معلومات احداثيات المنَمذَج الذي تم توليده
  Obj.transform.SetPositionAndRotation(trans; form.position,transform.rotation);
  
  MeshRenderer MeshR = Obj.AddComponent<MeshRenderer>();
  MeshFilter MeshF = Obj.AddComponent<MeshFilter>();

  Mesh BSmesh = new Mesh();
  SMR.BakeMesh(BSmesh);

  //الأمر الخاص بإلحاق المنَمذَج في مكون شكل المنَمذَج - Mesh Filter
  MeshF.mesh = BSmesh;
  //الأمر الخاص بإلحاق الخامة في مكون مظهر المنَمذَج - Mesh Renderer
  MeshR.material = BSMat;
  //أمر التدمير
  Destroy (Obj,5);
  }

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

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

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