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

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

شرح مفهوم Coyote Time

قد يكون القفز غير موجود في ألعاب المنصات، حيث لا يتمتع اللاعب بقدرٍ جيد من التحكم، وقد يفشل أحيانًا في القفز من حافة المنصات.

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

ملاحظة: أتى اسم هذه التقنية من شخصية الذئب Coyote الكرتونية الشهيرة التي لا تسقط حتى تنظر إلى الأسفل:

01 coyote

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

سنضيف عقدة Timer بالاسم CoyoteTimer ونضبطها على لقطة واحدة One Shot للتعامل مع ضبط الوقت، وتوجد بعض المتغيرات الجديدة التي نحتاجها لتعقّب وقت coyote كما يلي:

var coyote_frames = 6  # عدد الإطارات في الهواء المسموح بها للقفز
var coyote = false  # تتبّع ما إذا كنا في وقت‫ coyote أم لا
var last_floor = false  # حالة الإطار الأخير على الأرض

سنستخدم الإطارات لضبط المدة، وبالتالي يمكننا نقل ذلك إلى وقت ضبط طول العقدة Timer في التابع ‎_ready()‎ كما يلي:

$CoyoteTimer.wait_time = coyote_frames / 60.0

سنخزّن القيمة الحالية للتابع is_on_floor()‎ في كل إطار لاستخدامها في الإطار التالي، لذا يجب وضع ما يلي في الدالة ‎_physics_process()‎ بعد الدالة move_and_slide()‎:

last_floor = is_on_floor()

يجب التحقق مما إذا كانت الشخصية على الأرض أو في وقت Coyote عندما نكتشف إدخال القفز كما يلي:

    if Input.is_action_just_pressed("jump") and (is_on_floor() or coyote):
        velocity.y = jump_speed
        jumping = true

يبدأ وقت Coyote إذا مشى اللاعب بعد حافة المنصة، وبالتالي لم يَعُد على الأرض وكان على الأرض في الإطار السابق. يمكننا التحقق من ذلك وبدء تشغيل المؤقت إذا انتقلنا من الأرض إلى فوقها وفق التالي:

    if !is_on_floor() and last_floor and !jumping:
        coyote = true
        $CoyoteTimer.start()

تخبرنا العقدة CoyoteTimer متى تنتهي حالة coyote كما يلي:

func _on_coyote_timer_timeout():
    coyote = false

يمكن تطبيق العملية نفسها على الشخصيات ثلاثية الأبعاد.

ملاحظة: نُفِّذت شخصية القسم التالي باستخدام تقنية Coyote Time.

كيفية إعداد منصة متحركة في مشهد اللعبة

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

ملاحظة: يمكن أيضًا تطبيق هذه التقنية لتحريك المنصات باستخدام عقدة AnimationPlayer بدلًا من عقدة Tween، حيث سيبقى معظم الإعداد نفسه في كلتا الطريقتين، ولكن ستحرّك خاصية موضع position الجسم بدلًا من شيفرة Tween البرمجية.

الإعداد

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

إنشاء المنصة

يحتوي مشهد المنصة على العقد التالية:

  • Node2D المنصة المتحركة MovingPlatform: تكون العقدة الأب Node2D موجودةً لتعمل بوصفها نقطة ارتكاز أو نقطة بداية للمنصة، حيث سنحرّك موضع position المنصة بالتناسب مع هذه العقدة الأب
  • AnimatableBody2D: تمثل هذه العقدة المنصة نفسها، وهي العقدة التي ستتحرّك
  • Sprite2D: يمكن استخدام ورقة الشخصية الرسومية Sprite Sheet هنا أو صور فردية أو حتى عقدة TileMap
  • CollisionShape2D: لا يجب أن نجعل مربع الاصطدام كبيرًا جدًا، وإلّا فسيبدو اللاعب وكأنه يحوم فوق حافة المنصة

ستُعِدّ خامة Texture العقدة Sprite2D وشكل الاصطدام بطريقة مناسبة، ونضبط خاصية التزامن مع الفيزياء Sync to Physics على القيمة On في العقدة AnimatableBody2D، مما يضمن تحريك الجسم أثناء خطوة الفيزياء بما أننا نحرّكه في الشيفرة البرمجية، وبالتالي يكون متزامنًا مع اللاعب والأجسام الفيزيائية الأخرى.

سنضيف الآن السكربت التالي إلى العقدة الجذر Node2D:

extends Node2D

@export var offset = Vector2(0, -320)
@export var duration = 5.0

func _ready():
    start_tween()

func start_tween():
    var tween = get_tree().create_tween().set_process_mode(Tween.TWEEN_PROCESS_PHYSICS)
    tween.set_loops().set_parallel(false)
    tween.tween_property($AnimatableBody2d, "position", offset, duration / 2)
    tween.tween_property($AnimatableBody2d, "position", Vector2.ZERO, duration / 2)

حتى الآن قد استخدمنا بعض خيارات عقد Tween لجعل كل شيء يعمل بسلاسة مثل:

  • set_process_mode()‎: يضمن حدوث الحركة أثناء خطوة المعالجة الفيزيائية
  • set_loops()‎: يعمل على تكرار الانتقال التدريجي Tween
  • set_parallel(false)‎: تحدث جميع تغييرات tween_property()‎ في الوقت نفسه افتراضيًا، ويؤدي هذا التابع إلى حدوث هذين الأمرين الواحد تلوَ الآخر، وهما التحرك إلى أحد طرفي الإزاحة ثم العودة إلى البداية

يمكن ضبط حركة المنصة باستخدام هاتين الخاصيتين المُصدَّرتين، وهما الإزاحة offset التي يجب أن تضبطها لتحديد المكان الذي يتحرك فيه الانتقال التدريجي Tween بالنسبة لنقطة بدايته، و المدة duration التي يجب أن تضبطها لتحديد المدة التي تستغرقها لإكمال الدورة.

سنضيف الان بعض المنصات في المستوى أو العالم الخاص بنا ونجرّبها كما في المثال التالي:

ملاحظة: يمكن تنزيل شيفرة المشروع البرمجية من Github.

ترجمة -وبتصرّف- للقسمين Coyote Time و Moving Platforms من توثيقات Kidscancode.

اقرأ أيضًا


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

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

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



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

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

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

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   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.


×
×
  • أضف...