اذهب إلى المحتوى

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

1

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

تغيير دقة اللعبة

بداية سنغيّر دقة اللعبة قبل إنشاء المسار، حيث يبلغ حجم النافذة الافتراضية للعبة 1152x648 وسنعدّلها إلى 720x540 لتصبح أصغر حجمًا وأكثر توافقًا مع التصميم المطلوب.

نفتح المشهد الرئيسي Main للعبة بالنقر نقرًا مزدوجًا على main.tscn في قائمة نظام الملفات Filesystem dock الموجود على الشريط الجانبي الذي يعرض ملفات المشروع.

ننتقل بعدها إلى تبويب المشروع Project ثم نختار إعدادات المشروع Project Settings.

2

ننتقل بعد ذلك إلى القسم Display في القائمة الموجودة يسار نافذة إعدادات المشروع، ثم ونمرر إلى الأسفل حتى نجد قسم Window. ونغير قيمة العرض Width إلى 720، وقيمة الارتفاع Height إلى 540 كما في الصورة أدناه.

3

إنشاء مسار توليد الأعداء Spawn Path

نحتاج الآن إلى تصميم مسار ثلاثي الأبعاد وهنا نحتاج لاستخدام العقدة PathFollow3D لتوليد مواقع عشوائية على هذا المسار، الأمر هنا مشابه لما شرحناه عند إنشاء المشهد الرئيسي وتوليد الأعداد في اللعبة ثنائية الأبعاد في جودو، لكن رسم المسار في المجال ثلاثي الأبعاد أكثر تعقيدًا، حيث نريد أن يحيط المسار بنافذة عرض اللعبة، كي يظهر الأعداء مباشرة من خارج نطاق رؤية اللاعب.

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

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

يجب أن تكون نافذة العرض مقسمة إلى قسمين مع معاينة الكاميرا في الأسفل. إذا لم تكن كذلك فاضغط على‎‎ ctrl + 2‎‎ ‎‎أو cmd + 2 في حال كنت تستخدم نظام تشغيل macOS لقسمها إلى قسمين، ثم حدد عقدة Camera3D وانقر فوق مربع الاختيار Preview في أسفل نافذة العرض.

4

إضافة أسطوانات مؤقتة CylinderMesh

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

لإضافة شبكة اسطوانات مؤقتة، أضف عقدة Node3D جديدة كعقدة فرعية للعقدة الرئيسية وسمّها Cylinders، ثم حددها وأضف عقدة فرعية MeshInstance3D لنستخدمها في تجميع الأسطوانات. حدّد Cylinders لإضافة عقدة MeshInstance3D فرعية.

5

أسند CylinderMesh إلى الخاصية Mesh من قائمة الفاحص Inspector كما يلي:

6

عند العمل في جودو سيساعدنا التبديل بين طرق عرض مختلفة في نافذة المشهد Viewport على رؤية المشهد من زوايا مختلفة. وأحد هذه الزوايا هي Top View التي تعني المنظور العلوي، حيث سترى من خلالها المشهد كما لو كنت تنظر إليه من أعلى، مما يساعدك على ترتيب الأشياء بشكل دقيق.

اضبط نافذة العرض على خيار العرض العمودي العُلوي Top View باستخدام القائمة الظاهرة أعلى يسار نافذة العرض.

7

إذا كانت الشبكة الظاهرة تُشتت تركيزك، فيمكنك إيقاف عرضها أو تعديلها بالانتقال إلى قائمة العرض في شريط الأدوات والنقر فوق عرض الشبكة View Grid، عند النقر فوق هذا الخيار، سيتوقف عرض الشبكة على شاشة المحرر إذا كانت مُفعلة مسبقًا وإذا كنت تريد إظهار الشبكة مرة أخرى، يمكنك تفعيل الخيار من جديد.

8

يساعدك تحريك الأسطوانة في المشهد على مراقبة كيفية ظهورها من زاوية الكاميرا، ويسهل عليك ترتيب العناصر بشكل دقيق واحترافي في المستوى الأرضي، لذا ابدأ يتحريك الأسطوانة على طول المستوى الأرضي وانظر لمعاينة الكاميرا أسفل نافذة العرض. يُفضل أن تستخدم الالتقاط الشبكي Grid Sanp لفعل ذلك، حيث يمكنك تفعيله عن طريق النقر على أيقونة المغناطيس في شريط الأدوات كما في الصورة التالية أو الضغط على مفتاح Y.

9

حرك الأسطوانة بحيث تكون خارج رؤية الكاميرا مباشرة في الزاوية العلوية اليسرى كما في الصورة التالية.

10

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

لإنشاء نسخ من الشبكة ووضعها حول منطقة اللعب. نضغط على Ctrl + D‏ أو Cmd + D على نظام تشغيل macOS لتكرار العقدة، ويمكن أيضًا النقر بالزر الأيمن على العقدة في قائمة المشهد وتحديد خيار مضاعفة Duplicate، ثم تحريك النسخة لأسفل على طول المحور Z الأزرق حتى تصل لخارج معاينة الكاميرا مباشرة.

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

11

نحركهم إلى اليمين عن طريق سحب المحور X باللون الأحمر.

12

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

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

13

من قائمة الفاحص Inspector، نوسع قسم المادة Material لتظهر الخيارات الموجودة بداخله، سنضيف الخيار StandardMaterial3D إلى الحيز الأول في القائمة -وهو الحيز رقم 0- وبذلك، ستطبق المادة على الاسطوانات التي حددتها في المشهد.

14

15

انقر على أيقونة الجسم الكروي لفتح مورد المادة Material resource حيث ستحصل هنا على معاينة للمادة وقائمة طويلة من الخصائص لاستخدامها في إنشاء جميع أنواع الأسطح، من المعدن إلى الصخور أو الماء.

لتغيير اللون افتح قسم Albedo داخل إعدادات المادة:

16

اضبط اللون على خيار يتناقض مع الخلفية، مثل اللون البرتقالي الساطع.

17

يمكنك الآن استخدام الأسطوانات كدليل. ضعها في قائمة المشهد بالنقر فوق السهم الرمادي المجاور لها، ويمكنك التبديل بين عرضها وإخفائها من خلال النقر على أيقونة العين بجوار الأسطوانات.

18

الآن أضف عقدة فرعية Path3D إلى العقدة الرئيسيةMain. ستظهر في شريط الأدوات أربع أيقونات، انقر على أداة Add Point التي تحمل علامة "+" الخضراء كما يلي:

19

ملاحظة: يمكنك تمرير المؤشر فوق أي رمز لرؤية تلميح توضيحي يصف الأداة.

انقر وسط كل أسطوانة لإنشاء نقطة، ثم انقر فوق رمز إغلاق المنحنى Close Curve في شريط الأدوات لإغلاق المسار. في حال كانت أي من النقاط بعيدة قليلاً، يمكنك النقر فوقها وسحبها لإعادة تموضعها.

21.png

يجب أن يبدو مسارك كالتالي.

22.png

نحتاج إلى عقدة PathFollow3D لاختيار مواضع عشوائية عليها، لذا أضف PathFollow3D كعنصر فرعي لعقدة Path3D ثم أعد تسمية العقدتين إلى SpawnLocation و SpawnPath على التوالي فذلك سيوضّح حالة استخدامنا هنا.

نحن جاهزون الآن لبرمجة آلية توليد الأعداء في اللعبة.

توليد الأعداء عشوائيًا

انقر بالزر الأيمن على العقدة الرئيسية وأرفق سكريبت جديد لها من أجل توليد الأعداء بشكل دوري، أي على فترات زمنية منتظمة.

نضيف أولاً متغير إلى قائمة الفاحص Inspector بحيث يمكننا إسناد mob.tscn أو أي عدو آخر إليه كما يلي:

extends Node

@export var mob_scene: PackedScene 

وبما أننا نريد توليد العدو على فترات زمنية منتظمة، سنحتاج إلى العودة إلى المشهد وإضافة مؤقت، لكن قبل ذلك نحتاج إلى إسناد ملف mob.tscn إلى خاصية mob_scene أعلاه بخلاف ذلك سيكون فارغ.

عد إلى الشاشة ثلاثية الأبعاد وحدد العقدة الرئيسية، ثم اسحب mob.tscn من قائمة نظام الملفات إلى حيز مشهد العدو في قائمة الفاحص Inspector.

23.png

أضف عقدة Timer جديدة كعنصر فرعي للعقدة الرئيسية، وسمها MobTimer

24.png

اضبط من قائمة الفاحص Inspector وقت الانتظار Wait Time على القيمة 0.5 ثانية وفعّل التشغيل التلقائي Autostart حتى يبدأ توليد الأعداء تلقائيًا عند تشغيل اللعبة.

25.png

تطلق المؤقتات إشارة timeout في كل مرة تصل فيها إلى نهاية وقت انتظارها، وبشكل افتراضي يُعاد تشغيلها تلقائيًا، مما يؤدي إلى إصدار الإشارة بشكل متواصل، ويمكن الاتصال بها من العقدة الرئيسية لتوليد عدو كل 0.5 ثانية.

توجه إلى قائمة العقدة على اليمين أثناء تحديد MobTimer وانقر نقرًا مزدوجًا على إشارة timeout

26.png

صِلها بالعقدة الرئيسية

27.png

سيعيدك هذا إلى النص البرمجي مع دالة جديدة ‎_on_mob_timer_timeout()‎ هذه الدالة فارغة ولا تحتوي الدالة أي منطق برمجي لذا نحتاج لبرمجة منطق توليد العدو فيها عن طريق الخطوات التالية:

  1. إنشاء نسخة من مشهد العدو باستخدام mob_scene.instantiate()‎
  2. أخذ عينة عشوائية لموقع العدو باستخدام randf_range()‎
  3. الحصول على موضع اللاعب عبر الوصول إلى العقدة Player في المشهد
  4. استدعاء دالة initialize()‎ لإعداد العدو باستخدام الموقع العشوائي وموقع اللاعب 5 إضافة العدو كعنصر فرعي للعقدة الرئيسية في المشهد باستخدامadd_child()

بهذا يمكن توليد الأعداء بشكل دوري في نقاط عشوائية على المسار، مع الأخذ بعين الاعتبار مكان اللاعب ليتفاعل العدو معه كما توضح الشيفرة التالية:

func _on_mob_timer_timeout():
    # إنشاء نسخة جديدة من مشهد العدو
    var mob = mob_scene.instantiate()

    # اختر مكان عشوائي على‫ SpawnPath
    # ‫نخزن المرجع إلى عقدة SpawnLocation
    var mob_spawn_location = get_node("SpawnPath/SpawnLocation")
    # ونعطيها انزياح عشوائي
    mob_spawn_location.progress_ratio = randf()

    var player_position = $Player.position
    mob.initialize(mob_spawn_location.position, player_position)

    # توليد الأعداء عن طريق إضافتها إلى المشهد الأساسي
    add_child(mob) 

تُنتج دالة randf()‎ قيمة عشوائية بين 0 و1، وهي تمثل القيمة المتوقعة للمتغير progress_ratio في عقدة PathFollow. حيث تشير 0 إلى بداية المسار، وتشير 1 إلى نهايته. وبما أن المسار الذي حددناه يحيط بنافذة عرض الكاميرا، لذا فإن أي قيمة عشوائية بين 0 و1 ستحدد موقعًا عشوائيًا على طول حواف نافذة العرض.

فيما يلي الكود البرمجي الكامل للملف main.gd للرجوع إليه عند الحاجة:

extends Node

@export var mob_scene: PackedScene


func _on_mob_timer_timeout():
    # إنشاء نسخة جديدة من مشهد العدو
    var mob = mob_scene.instantiate()

    # اختر مكان عشوائي على‫ SpawnPath
    # ‫نخزن المرجع إلى عقدة SpawnLocation
    var mob_spawn_location = get_node("SpawnPath/SpawnLocation")
    #  ونعطيها انزياح عشوائي
    mob_spawn_location.progress_ratio = randf()

    var player_position = $Player.position
    mob.initialize(mob_spawn_location.position, player_position)

    #  توليد الأعداء عن طريق إضافتها إلى المشهد الأساسي
    add_child(mob)

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

28.png

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

الخلاصة

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

ترجمة -وبتصرف- لقسم Spawning monsters من توثيق جودو الرسمي.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...