نشرح في هذا المقال طريقة إنشاء جسم يمثل سفنية تتحرك بطريقة واقعية في الفضاء باستخدام عقدة الجسم الصلب RigidBody2D
، حيث يوفر محرك الألعاب جودو أنواعًا مختلفة من الأجسام الفيزيائية ومن ضمنها عقدة RigidBody2D
التي تناسب جسمًا يتحرك تلقائيًا وفقًا لقوانين الفيزياء. قد يكون استخدام هذه العقدة مربكًا بعض الشيء لأنها غير قابلة للتحريك المباشر بطريقة مشابهة لعقدة الشخصية CharacterBody2D
ومن يتحكم بالكامل هو محرك فيزياء جودو الداخلي Godot physics engine، وبالتالي لا يمكننا ببساطة تغيير موقعها مباشرة من أجل تحريكها بل علينا تطبيق قوى فيزيائية عليها لتحقيق الحركة المطلوبة.
ننصح قبل بدء العمل بإلقاء نظرة على توثيق الواجهة البرمجية RigidBody2D لفهم خصائصها بشكل أعمق.
بناء الحركة
سننشئ مشهد جديد ثنائي الأبعاد في جودو ونستخدم فيه العقد التالية:
RigidBody2D (Ship) ├── Sprite2D └── CollisionShape2D
وإليكم وظيفة كل عقدة منها:
-
تمثل
RigidBody2D(Ship)
العقدة الرئيسية للجسم الصلب الذي نريد تحريكه، والذي يتفاعل مع البيئة ويتأثر بقوانين الفيزياء -
تمثل العقدة
Sprite2D
الشكل المرئي للجسم الصلب، وهي في حالتنا صورة سفينة الفضاء التي تتحرك تلقائيًا مع الجسم الفيزيائي الصلب -
تستخدم العقدة
CollisionShape2D
لتحديد شكل وحجم منطقة التصادم للجسم الصلب، وهي ضرورية كي تتعرف الفيزياء على حدود الجسم وتتفاعل معه بشكل صحيح عند اصطدامه بأجسام أخرى
توجيه الشخصية
عندما نحرك جسم صلب RigidBody2D
في جودو، فإن اتجاهه الأمامي الافتراضي أي الاتجاه الذي يتحرك فيه يُعد دومًا هو الاتجاه الموجب للمحور X
أي نحو اليمين في المشهد، لذا علينا في البداية توجيه الجسم الصلب بالشكل الصحيح إذا لم يكن كذلك. هذا الأمر مهم لأننا عندما نطبق قوى أو سرعة على الجسم فإن هذه القيم تُحسب بناءً على المحاور المحلية للجسم، لذا إذا لم يكن الجسم موجّهًا أصلاً نحو اليمين فستكون حركته غير صحيحة أو غير متوقعة. وإن كانت الأيقونة أو صورة الشخصية تتجه باتجاه معاكس، علينا أن ندوّر العقدة Sprite2D
وليس الجسم الأب نفسه RigidBody2D
حتى نوجهها بالشكل الصحيح.
كما سنستخدم المدخلات التالية في خريطة الإدخال Input Map:
المُدخل | المفتاح |
---|---|
thrust
|
w أو ↑ |
rotate_right
|
d أو → |
rotate_left
|
a أو ← |
بعدها، سنضيف سكريبت إلى الجسم الصلب ونعرّف فيه بعض المتغيرات:
extends RigidBody2D @export var engine_power = 800 @export var spin_power = 10000 var thrust = Vector2.ZERO var rotation_dir = 0
يحدد أول متغيران كيفية التحكم بحركة سفينة الفضاء. إذ يتحكم المتغير engine_power
بالتسارع أي سرعة الحركة للأمام، بينما يتحكم المتغير spin_power
بسرعة دوران السفينة. ويُضبط كل من thrust
و rotation_dir
بناءً على مدخلات المستخدم، وهذا ما سنفعله تاليًا:
func get_input(): thrust = Vector2.ZERO if Input.is_action_pressed("thrust"): thrust = transform.x * engine_power rotation_dir = Input.get_axis("rotate_left", "rotate_right")
في البداية، تكون قيمة thrust
صفرًا، مما يعني أن السفينة الفضائية لا تتحرك إلى الأمام. عندما يضغط المستخدم مفتاح الدفع مثل السهم العلوي أو مفتاح W، فإننا نضبط thrust
بحيث يحدد الشعاع الذي يوجه الحركة الأمامية للسفينة. في الوقت نفسه، تتغير قيمة rotation_dir
بمقدار 1
بناءً على مفتاح الإدخال الذي يضغط عليه المستخدم، سواء كان لليمين أو اليسار.
يمكن للسفينة الفضائية البدء بالطيران عند تطبيق القيم التالية في الدالة (physics_process(delta_.
func _physics_process(_delta): get_input() constant_force = thrust constant_torque = rotation_dir * spin_power
ستحلق المركبة الآن في الفضاء، لكن سنجد صعوبة في التحكم بها. حيث سيكون الدوران سريعًا جدًا، وستتسارع بشدة لتغادر الشاشة بعدها، وهنا لا بد من التوقف عن تطبيق فيزياء الفضاء الحقيقية، فطالما أنه لا احتكاك في الفضاء ستتسارع المركبة بسرعة، لهذا من الأسهل في مثالنا أن ندفع المركبة لتتوقف عندما لا تطبَّق عليها قوة دفع، ويمكننا تنفيذ هذا الأمر باستخدام التخميد damping
.
لننتقل إلى خصائص العقدة ومنها إلى Linear
ثم Damp
و Angular
ثم Damp
ونضبط قيمتي هاتين الخاصيتين على 1
و 2
على الترتيب. تحدّ هاتان القيمتان من سرعة الحركة وسرعة الدوران مما يسبب توقف السفينة الفضائية.
ملاحظة: يمكن أن نجرّب تغيير قيم هذه الخاصيات ونرى كيف تتفاعل مع engine_power
و spin_power
.
العودة إلى الشاشة
تشبه عملية إعادة سفينة الفضاء إلى الجهة المقابلة من الشاشة بعد خروجها من أحد الأطراف انتقالًا لحظيًا عبر المكان. لكن إن حاولنا تعديل خاصية position
مباشرةً، فستقفز السفينة فورًا إلى الموقع الجديد، وقد يؤدي ذلك إلى سلوك غير متوقع، لأن محرّك فيزياء جودو يستمر في التحكم بحركة الجسم الصلب.
للتغلب على هذه المشكلة، نستخدم دالة رد النداء ()integrate_forces_
الخاصة بالعقدة RigidBody2D
، والتي تتيح لنا تعديل الخصائص الفيزيائية مثل الموقع والسرعة بشكل مباشر ومتزامن مع دورة محرك الفيزياء دون أن تتعارض معها.
لننتقل الآن إلى screensize
في أعلى السكريبت:
@onready var screensize = get_viewport_rect().size
نضيف بعد ذلك دالة جديدة باسم ()integrate_forces_:
func _integrate_forces(state): var xform = state.transform xform.origin.x = wrapf(xform.origin.x, 0, screensize.x) xform.origin.y = wrapf(xform.origin.y, 0, screensize.y) state.transform = xform
نلاحظ أن الدالة ()integrate_forces_
تستقبل معاملًا باسم state
، وهو كائن من النوع PhysicsDirectBodyState2D
يمثل الحالة الفيزيائية الحالية للجسم الصلب. يحتوي هذا الكائن على معلومات مثل موضع الجسم position
والقوى المؤثرة forces
والسرعة velocity
في الاتجاهات المختلفة وغيرها من الخصائص الفيزيائية.
وبالتالي يمكن أن نحصل من خلال state
على التحويل الحالي للجسم current transform أي موقعه واتجاهه، ثم نعدّل إحداثيات الموقع باستخدام الدالة ()wrapf
لتطبيق التفاف حول الشاشة مما يعني أن الجسم سيتجاوز حافة الشاشة ويظهر من الجهة المقابلة لإعطاء تأثير الحركة المستمرة. وأخيرًا، نُعيد ضبط التحويل الجديد داخل state
لضمان استمرار حركة الجسم بشكل طبيعي وواقعي.
ستبدو الحركة كما في الصورة التالية:
الانتقال الفوري
لنلقِ نظرة على مثال آخر يوضح استخدام ()integrate_forces_
لتغيير حالة الجسم دون مشكلات. لنضف آلية انتقال آني أو فوري بحيث يتمكن اللاعب من نقل المركبة الفضائية فورًا إلى موقع عشوائي داخل الشاشة عند الضغط على مفتاح مخصص.
نضيف بداية متغيرًا جديدًا:
var teleport_pos = null
نحضّر تاليًا موقعًا عشوائيًا ضمن الدالة ()get_input
:
if Input.is_action_just_pressed("warp"): teleport_pos = Vector2(randf_range(0, screensize.x), randf_range(0, screensize.y))
وأخيرًا وضمن الدالة ()integrate_forces_
سنستخدم teleport_position
إن كان موجودًا ومن ثم نمسحه:
if teleport_pos: physics_state.transform.origin = teleport_pos teleport_pos = null
وبهذا نكون قد أضفنا ميزة الانتقال الفوري للمركبة الفضائية بشكل آمن ومتوافق مع نظام فيزياء جودو.
الخاتمة
بهذا نكون وصلنا لختام هذا المقال الذي استعرضنا فيه كيفية استخدام محرك الفيزياء في جودو لتحريك الأجسام الصلبة والتحكم بها بشكل دقيق لتوفير تجربة حركة تفاعلية واقعية ضمن بيئات ثنائية وثلاثية الأبعاد مع التحكم الكامل في حركة الأجسام. بإمكانك تحميل المثال كاملًا عبر مستودعه على جيتهب أو من هنا مباشرة asteroids_physics.zip
ترجمة -وبتصرف- للمقال: Asteroids-style Physics (using RigidBody2D)
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.