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

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

الإطباق على هدف

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

لا بد من تطبيق عزم دوراني torque حتى نتمكن من تدوير الجسم، وبمجرد أن يبدأ الجسم بالدوران، علينا تقليل عزم الدوران تدريجيًا مع اقتراب hg[sl من الوجهة النهائية بحيث لا يفرط الجسم في الدوران ويتوقف في الاتجاه الصحيح بدقة. تُعدُّ هذه حالة مثالية لتطبيق الجداء النقطي المعروف أيضًا باسم الداخلي dot product فهو مناسب جدًا لتحديد الاتجاه المطلوب للوصول للوجهة النهائية.

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

dot cross 01

ناتج الجداء النقطي موجب

هذا يعني أن الزاوية بين اتجاه الجسم الحالي واتجاه الوجهة أقل من 90 درجة، أي أن الجسم يحتاج إلى تعديل بسيط، أو لا يحتاج تعديل للوصول للوجهة لأنه قريب من الاتجاه الصحيح بالفعل.

ناتج الجداء النقطي صفر

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

ناتج الجداء النقطي سالب

هذا يشير إلى أن الزاوية بين اتجاه الجسم واتجاه الوجهة أكبر من 90 درجة، مما يعني أن الجسم يحتاج إلى التدوير الكامل نحو الاتجاه المعاكس. وبهذا، تكون الوجهة خلف الجسم.

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

لنلقِ نظرة على الكود التالي المكتوب بلغة GDScript لتدوير جسم ثنائي الأبعاد 2D باتجاه هدف معين بتطبيق عزم دوراني torque:

extends RigidBody2D

var angular_force = 50000
var target = position + Vector2.RIGHT

func _physics_process(delta):
    var dir = transform.y.dot(position.direction_to(target))
    constant_torque = dir * angular_force

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

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

تفادي مشكلات تدوير الجسم الصلب RigidBody2D

يمكننا تفادي تعقيدات تحريك الجسم الصلب بالامتناع عن تدوير الجسم الصلب نفسه RigidBody2D، ونعمل بدلًا من ذلك على تعديل الخاصية rotation لشخصية الابن child sprite كي يتوجه نحو الهدف. وبالإمكان حينها استخدام التابعين ()lerp و ()Tween لجعل الحركة الدورانية سلسلة قدر المستطاع. ويعد هذا الحل مناسبًا في كثير من الحالات، حيث يمكن أن يكون للجسم الأساسي اتجاهه الخاص بينما تتجه الشخصية أو العنصر المرتبط به في اتجاه مختلف نحو الهدف. إذ يمكن للجسم الأساسي أن يتحرك في اتجاه معين، بينما يمكن للشخصية الملحقة به مثل الرأس أو السلاح أن تدور بشكل مستقل دون الحاجة لأن يكون توجيهها مطابقًا تمامًا لتوجيه الجسم الأساسي.

تحرك جسم نحو الهدف

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

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

يفيدنا استخدام التابع ()Vector2.distance_to لحل هذه المشكلة بشكل ممتاز، فهو يحسب المسافة بين الجسم والهدف، ويساعدنا على  استخدام هذه المسافة لتحديد مقدار القوة المطلوب تطبيقها فعندما يكون الجسم بعيدًا، نطبق قوة أكبر، وكلما اقترب من الهدف، نخفض القوة تدريجيًا لضمان توقف سلس، وبهذه الطريقة، نحقق حركة طبيعية دون اهتزازات أو توقف مفاجئ.

لنلقِ نظرة على الكود التالي الذي يجعل الجسم الصلب RigidBody2D  يتحرك نحو هدف معين بطريقة سلسة:

# تحريك الجسم بسلاسة نحو الهدف
extends RigidBody2D

var linear_force = 5
var target = position


func _physics_process(delta):
    var dist = position.distance_to(target)
    constant_force = dir * linear_force * dist

يحسب الكود أعلاه القوة الخطية المطلوبة لتحريك الجسم نحو الهدف بناء على المسافة بين الجسم المتحرك والهدف dist. تزداد القوة عندما يكون الجسم بعيدًا عن الهدف وتقل تدريجيًا مع الاقتراب من الهدف، مما يجعل الحركة تبدو طبيعية وسلسة.

أهمية الخاصية linear_damp

إن حاولنا استخدام إعدادات العقدة RigidBody2D الافتراضية في جودو، فقد نلاحظ أحيانًا تجاوز الجسم الصلب للهدف. يعود السبب إلى الخاصية linear_damp التي تأخذ القيمة 1 افتراضيًا. تمثل هذه القيمة معامل الاحتكاك friction، وتتحكم بكيفية تخميد أو توقف الجسم الصلب عن الحركة عند توقف القوى المحرّكة. فهي تعمل مثل الاحتكاك، مما يؤدي إلى تقليل سرعة الجسم تدريجيًا عندما لا تكون هناك قوة تدفعه.

عندما تكون قيمة هذه الخاصية 0، فهذا يعني أن الجسم لن يتباطأ تلقائيًا، بل سيستمر في التحرك بسرعة ثابتة ما لم تؤثر عليه قوة أخرى، مثل الجاذبية أو الاحتكاك. أما عندما تكون قيمتها 1 أو 2، فإن تأثير التخميد يزداد، مما يؤدي إلى تقليل سرعة الجسم تدريجيًا حتى يتوقف عندما لا يكون هناك قوة تحركه.

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

الخاتمة

تعلمنا في مقال اليوم كيفية تحريك وتدوير جسم صلب RigidBody2D  في جودو بشكل سلس نحو هدف معين باستخدام القوى والعزم الدوراني، كما شرحنا كيفية التحكم في التباطؤ باستخدام الخاصية linear_damp لضمان حركة طبيعية للجسم.

ترجمة -وبتصرف- للمقالين: RigidBody2D: Look at Target و RigidBody2D: Move to Target

اقرأ أيضًا


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

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

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



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

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

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

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


×
×
  • أضف...