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

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

001 سحب وإفلات جسم صلب

إعداد الجسم الصلب

لننشئ مشروع لعبة جديدة ثنائية الأبعاد في جودو ونعمل مع كائن يمثل الجسم الصلب بإضافة العقدتين Sprite2D و CollisionShape2D. بإمكاننا أيضًا إضافة العقدة PhysicsMaterial إن أردنا ضبط خاصيتي الارتداد Bounce والاحتكاك Friction

كما سنستخدم الخاصية freeze لإبعاد الجسم عن سيطرة محرّك الفيزياء عندما نسحبه. وطالما أننا نريد من الجسم الصلب أن يكون قابلًا لحركة، لا بد من ضبط قيمة الخاصية Freeze في القسم Mode على القيمة kinematic بدلًا من القيمة الافتراضية Static.

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

نضيف سكريبت برمجي للجسم الصلب ثم نصل الإشارة _input_event الخاصة به كما يلي.

extends RigidBody2D

signal clicked

var held = false

func _on_input_event(viewport, event, shape_idx):
    if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
        if event.pressed:
            print("clicked")
            clicked.emit(self)

نبث الإشارة عندما نلتقط حدث النقر على الفأرة التي تتضمن مرجعًا إلى الجسم. ونظرًا لوجود عدة أجسام، سنترك أمر إدارة حالة الأجسام إن كانت قابلة للسحب أو أنها في حالة held أي إيقاف للمشهد الرئيسي main scene. فإن كان الجسم يُسحب، نغيّر موقعه باتباع حركة الفأرة.

func _physics_process(delta):
    if held:
        global_transform.origin = get_global_mouse_position()

فيما يلي الدالتان اللتان سنستدعيهما عند التقاط الجسم وإفلاته. ولنتذكر أن تغيير قيمة الخاصية freeze إلى true سيزيل الجسم من عمليات محرّك الفيزياء. 

سنلاحظ أن بقية الأجسام لا تزال قادرة على الاصطدام بهذا الجسم، فإن لم نرغب بهذا السلوك، نستطيع تعطيل الخاصية collision_layer مع أو بدون الخاصية collision_mask، ولا ننسى إعادة تمكينهما عند الإفلات.

func pickup():
    if held:
        return
    freeze = true
    held = true

func drop(impulse=Vector2.ZERO):
    if held:
        freeze = false
        apply_central_impulse(impulse)
        held = false

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

المشهد الرئيسي

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

extends Node2D

var held_object = null

func _ready():
    for node in get_tree().get_nodes_in_group("pickable"):
        node.clicked.connect(_on_pickable_clicked)

نعرّف بعد ذلك الدالة التي نربط بها الإشارات، وتضبط هذه الدالة قيمة held_object حتى نعرف بوجود جسم يُسحب حاليًا، ونستدعي التابع ()pickup الخاص بالجسم.

func _on_pickable_clicked(object):
    if !held_object:
        object.pickup()
        held_object = object

عندما نحرر الفأرة خلال السحب بإمكاننا تنفيذ الخطوات المعاكسة.

func _unhandled_input(event):
    if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
        if held_object and !event.pressed:
            held_object.drop(Input.get_last_mouse_velocity())
            held_object = null

لنلاحظ كيف استخدمنا هنا التابع ()get_last_mouse_velocity لتمرير الدفع إلى الكائن. علينا أن ننتبه إلى ذلك جيدّا. مع ذلك، سنجد أننا نطلق الجسم الصلب بسرعة كبيرة وخاصة إذا كانت قيمة الخاصية mass للجسم قليلة. لهذا، من الأجدى أن نحدد القيمة العظمى للكتلة على قيمة مناسبة باستخدام التابع ()clamp. يمكن تجربة عدة قيم حتى نحدد ما يناسب لعبتنا.

الخاتمة

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

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

يمكن تحميل المثال كاملًا من هذا الرابط لفهمه بصورة جيدة وتجربة التعديل عليه، أو تحميله مباشرة من هنا rigidbody_drag_drop-master.zip

ترجمة -وبتصرف- للمقال: RigidBody2D Drag and Drop

اقرأ أيضًا

 


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

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

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



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

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

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

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


×
×
  • أضف...