كيفية انشاء كائنات جديدة في محرك godot عن طريق class_name

Godot

من الأمور التي يجب أن تعرفها حول محرك غودو هو أنه يحتوي على مجموعة ضخمة من العُقد الجاهزة. والعُقد يمكن اعتبارها كصنف Class وتعتبر العقد من المكونات الأساسية للمحرك. 

العُقدة تحتوي بداخلها على مجموعة من المتغيرات والدوال التي تصف وظيفتها.
فعلى سبيل المثال، لدينا عقدة CharacterBody2D التي تحتوي على العديد من المتغيرات والدوال المتواجدة داخلها كما ترى في الصورة التالية

يتميز المحرك بوجود العديد من العقد الجاهزة التي تساعدك في إنشاء مشروعك، وبإمكانك إنشاء كائنات من هذه العقد  والوصول إلى المتغيرات الموجودة بداخلها واستخدامها.

على سبيل المثال، يمكنك إنشاء كائن من عقدة Marker2D واستخدام المتغيرات التي بداخله، مثل ما ترى في الكود التالي:

var point  = Marker2D.new()
point.position = Vector2(5, 10)
print(point.position) # (5, 10)


في هذا المثال، قمنا بإنشاء كائن من العقدة Marker2D باستخدام الدالة new()، ثم قمنا بتعيين قيمة لمتغير position الموجود داخل العقدة. بعد ذلك، قمنا بطباعة قيمة المتغير position باستخدام الدالة print()، والتي ستعرض (5, 10) كناتج للطباعة.

تعامل المحرك مع المشاهد

واحدة من أساسيات المحرك, انه يتعمل مع المشاهد Scenes كأصناف أيضًا. يمكنك استدعاء أي مشهد من أي مكان في المحرك وإنشاء كائن منه.
على سبيل المثال، لنفترض أن لدينا مشهد بسيط للاعب يُسمى Player. يمكننا استدعاءه من أي ملف آخر بهذه الطريقة:

var playerScene = preload("res://Player.tscn")
var player = playerScene.instantiate()
print(player.DAMAGE)

بهذا الشكل، قمنا بإنشاء كائن من مشهد اللاعب وقمنا بطباعة قيمة متغير الضرر DAMAGE من داخل اللاعب، وهو المتغير الذي يُمثل الضرر الذي يلحقه اللاعب للعدو.

تلاحظ أننا اضطررنا لاستدعاء المشهد عن طريق تحميله مسبقًا باستخدام الدالة preload() بوضع مسار الملف “res://Player.tscn” واستدعاءه وعمل كائن منه عن طريق دالة instantiate().

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

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

فكرة الـ class_name لتعريف المشهد للمحرك

تأتي ميزة الـ class_name في المحرك لتمكينك من تعريف اسم لصنف الملف الأساسي في المشهد.

في الصورة التالية، لدينا مشهد بسيط للاعب وستلاحظ أننا في بداية الكود الخاص بملف اللاعب قمنا بكتابة class_name Player، وهذا يعني أن المحرك سيتعرف على هذا المشهد أو الملف بأنه صنف يُسمى Player. بالطبع، نظرًا لأن المشهد يرث من CharacterBody2D، فإن الـ Player سيرث جميع خصائصها أيضًا.

هكذا عندما ترغب في إنشاء كائن من اللاعب Player، ستصبح العملية أسهل. يمكنك استخدام Player.new() كما يلي:

var player = Player.new()
print(player.DAMAGE)

وذلك لأن المحرك الآن يتعامل مع Player على أنه نوع بيانات جديد أو صنف جديد.

وعندما ترغب في إنشاء مشهد جديد، يمكنك تحديد العقدة الرئيسية للمشهد وجعلها من نوع Player الذي قمت بتعريفه سابقًا. بهذه الطريقة،

 سيقوم المحرك بإنشاء المشهد والعقدة الرئيسية ستكون من نوع Player وترث من CharacterBody2D. 

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

لكن لأننا عرفنا متغيري السرعة SPEED  والضرر DAMAGE فقط فستجدهما متواجدين كما ترى

 هل يرتبط الـ class_name بالمشاهد فقط ؟

لا، بل يمكنك استخدام class_name  مع أي ملف بشكل مستقل عن أي مشهد، فيمكنك إنشاء ملف ما مستقل تمامًا وتعيين class_name له بأن يكون على سبيل المثال صنف باسم عدو Enemy ليمثل أي عدو بشكل عام، ومن ثم يمكنك تعريف الدوال والمتغيرات التي ترغب في وجودها داخله.

هنا في هذا المثال، قمنا بإنشاء ملف مستقل تمامًا عن أي مشهد وجعلناه من نوع عدو Enemy ويرث من Node2D.
ثم أضفنا بعض المتغيرات والدوال التي نرغب في وجودها داخل أي العدو، كالصحة health و دالة الأذى hurt والتى تخبرنا ان العدو تلقى ضرر بمقدار معين، وعندنا يصل مقدار الصحة للصفر فسيتم مسح العدو من المشهد.

الآن ماذا سيفعل المحرك مع صنف العدو الذي أنشأناه للتو ؟ هل تتذكر ما قلناه؟

  • سيتعامل مع صنف العدو على أنها نوع بيانات جديد أو صنف جديد خاص بنا. يمكننا إنشاء أي مشهد وجعل العقدة الرئيسية (أو أي عقدة بشكل عام) ترث من Enemy. 
  • بوجود هذا الصنف، يمكننا اعتباره نوع بيانات جديد، وبالتالي يمكننا تعريف متغيرات أو كائنات من نوع عدو أيضًا.
  •  يمكننا أيضًا إنشاء مصفوفة تحتوي فقط على كائن من نوع عدو أي يرث فقط من Enemy. بالإضافة إلى ذلك، يمكننا كتابة دوال تستقبل أي كائن نوع عدو.

أريدك أن تدرك أن المحرك اصبح يتعامل مع الـ Enemy كنوع بيانات جديد أو كصنف جديد تمامًا، كما يتعامل مع العُقد الأخرى أو أنواع البيانات الأخرى مثل الـ string و int و float وغيرها. الأمر نفسه ينطبق على صنف اللاعب الذي قمنا بتعريفه سابقًا.

إنشاء عدو زومبي يرث من Enemy

الآن يمكنك إنشاء عدو جديد ولنفترض أنه سيكون عدو الزومبي Zombie. أولاً، سنقوم بإنشاء مشهد الزومبي وتحديد العقدة الرئيسية له. ستلاحظ وجود Enemy الصنف الذي أنشأناه للتو.

الآن نستطيع أن ننشيء عدو الزومبي كما نريد كما ترى هنا

ستلاحظ أنه يقوم بعمل extends Enemy أي ان هذا المشهد سيرث كل شيء من مشهد العدو
يمكنك أن تلاحظ أنه بما أن الزومبي يرث من Enemy، سيكون لديه جميع المتغيرات والدوال المتواجدة في العدو، بما في ذلك دالة hurt والمتغير health. يمكنك الضغط على F1 والبحث عن Enemy لمشاهدة كافة تفاصيله.

ستلاحظ أنه يُخبرك أيضًا من الذي يرث Enemy، وفي حالتنا هذه فقط الـ Zombie يرثه.
تخيل معي أن لديك 10 أعداء، يمكنك أن تأتي هنا وترى جميع الأعداء الذين يرثون من العدو.
تطبيق عملي بسيط
ستلاحظ اننا في الكود السابق الخاص بعدو الزومبي كا لدينا دالة إشارة area_2d_body_entered, تنشط عند اكتشاف أي جسم يدخل مجال العدو.

func _on_area_2d_body_entered(body):
  var player = body as Player # نحدد أن الـ body يجب أن يكون Player
  # في حالة أنه ليس من نوع Player ستكون قيمة المتغير هنا بـ null
  # لذا لن يتحقق الشرط حينها
  if player:
    print('Player hurts ', name)
    # نستدعي الدالة الخاص بالعدو لنحدد انه اصيب بمثدار الضرر الذي الحقه اللاعب له  
    hurt(player.DAMAGE) 

هنا تقوم الدالة أولًا بفحص  إن  كان هذا الجسم body هو  لاعب ام لا،  

هنا نستخدم اللاعب Player كنوع بيانات كما تلاحظ، ان كان الجسم ليس من نوع اللاعب فسيصبح المتغير player قيمته بـ null ولن يدخل في الشرط، أما ان كان الجسم من نوع اللاعب بالفعل حينها ندخل في الشرط.

داخل الشرط نبدأ في استدعاء دالة hurt لنمثل أن العدو تلقى ضررًا ما من اللاعب.

هل تتذكر مكان وجود دالة الأذى hurt؟
توجد بالطبع داخل صنف العدو. تذكر أن Zombie يرث من Enemy، لذا فهو يحصل على جميع المتغيرات والدوال الموجودة في صنف العدو كما ذكرنا.

 في حالة أن لعبتك هي لعبة إطلاق نار، وأن اللاعب يقتل الأعداء باستخدام الرصاصات التى تطلقها، فان فهمت الـ class_name وكيف تستخدمه فحينها ستتمكن م كتابة الكود بشكل أبسط هكذا

هكذا، الرصاصة ستصيب فقط أي جسم من نوع عدو Enemy. إذا كان الجسم شجرة أو مبنى، لن يتم تنفيذ الشرط. وإذا أضفت فيما بعد 10 أعداء جدد (يرثون من Enemy)، سيستمر الكود في العمل بدون أن تحتاج لتعديله.

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

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