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

يحتاج أي مطور ألعاب لمعرفة بعض المفاهيم الرياضية الأساسية ليتحكم في انتقال الشخصيات من حالة لأخرى بانسيابية ويتحكم في اتجاهاتها وتمكينها من معرفة ماذا يوجد أمامها وخلفها، وسنناقش في مقال اليوم مفاهيم تستخدم بكثرة في تطوير اﻷلعاب، مثل الاستيفاء الخطي linear interpolation -أو lerp اختصارًا- والجداء الداخلي أو النقطي أو السلمي Dot Product، والجداء الخارجي أو الشعاعي Cross Product.
قد تبدو هذه المصطلحات مقعدة وغامضة لمن يسمعها لأول مرة، لكن لا داعي للقلق فبعد قراءة هذا المقال ومعرفة تطبيقاتها العملية في برمجة اﻷلعاب ستغدو سهلة وبسيطة.

الاستيفاء العددي

تُعطى الصيغة اﻷساسية للاستيفاء الخطي رياضيًا كالتالي:

func lerp(a, b, t):
    return (1 - t) * a + t * b

يمثل كل من a و b قيمتين، بينما تمثل t مقدار الاستيفاء بينهما أي النسبة التي تحدد إلى أي درجة ننتقل من a إلى b. وتتراوح قيم t نمطيًا بين 0 وعندها سيعيد الاستيفاء قيمة a، وبين القيمة 1 وعندها سيعيد الاستيفاء قيمة b. يعطي تابع الاستيفاء قيمة ما بين a و b كما في المثال التالي:

x = lerp(0, 1, 0.75) # x is 0.75
x = lerp(0, 100, 0.5) # x is 50
x = lerp(10, 75, 0.3) # x is 29.5
x = lerp(30, 2, 0.75) # x is 9

يُدعى هذا الاستيفاء بالاستيفاء الخطي لأنه يعدّ المسافة بين نقطتي الاستيفاء خطًا مستقيمًا.

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

extends Sprite2D

var time = 0
var duration = 2 # المدة الزمنية للتأثير

func _process(delta):
    if time < duration:
      time += delta
      modulate.a = lerp(1, 0, time / duration)
      scale = Vector2.ONE * lerp(1, 5, time / duration)

الاستيفاء الشعاعي

من الممكن الاستيفاء أيضًا بين شعاعين وهذا يعني إيجاد شعاع جديد يقع بينهما بناءً على مقدار معين t تمامًا مثل الاستيفاء بين رقمين، لكن هنا نتعامل مع اتجاهات أو مواقع في الفضاء، إذ توفر كلا العقدتين Vector2 و Vector3 التابع ()linear_interpolate لتنفيذ اﻷمر.

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

var forward = -transform.basis.z
var left = transform.basis.x
var forward_left = forward.linear_interpolate(left, 0.5)

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

extends Sprite2D

var target

func _input(event):
    if event is InputEventMouseButton and event.pressed:
      target = event.position

func _process(delta):
    if target:
      position = position.linear_interpolate(target, 0.1)

الجداء الشعاعي الداخلي والخارجي

يمكن تنفيذ عمليتي جداء على اﻷشعة هما الجداء الداخلي السلمي أو النقطي dot product والذي تكون نتيجته عدد، والجداء الخارجي أو الشعاعي والذي تكون نتيجته شعاعًا.

الجداء الداخلي

هو عملية حسابية على شعاعين تكون نتيجته عدد حقيقي، وتمثل عادة على أنها مسقط شعاع A على حامل الشعاع اﻵخر B:

01 dot cross

تُعطى الصيغة الرياضية للجداء الداخلي بالعلاقة:

02 dot product

حيث:

  • θ : هي الزاوية بين الشعاعين
  • ||A||: طويلة الشعاع اﻷول
  • ||B||:طويلة الشعاع الثاني

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

03 dot product  normalized

تشير هذه العلاقة إلى الارتباط المباشر بين الجداء الداخلي والزاوية بين الشعاعين، وطالما أن cos(0)=1 و cos(180)=-1 ستدل قيمة الجداء السلمي على اتجاه الشعاعين بالنسبة لبعضهما، فهما في الزاوية 0 منطبقان وفي الزاوية 180 في اتجاهين مختلفين:

04 dot product angle

وسنرى في فقرة قادمة كيف نستفيد من هذا الجداء عمليًا.

الجداء الخارجي

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

05 cross product

تعطى طويلة الشعاع الناتج عن الجداء الخارجي بالعلاقة:

A x B = ||A||.||B||.sin(θ) //هي الزاوية بين الشعاعين θ

وإن كانت طويلة كل من الشعاعين هي الواحد ستكون نتيجة الحساب أبسط، إذ تكون طويلة الشعاع الناتج قيمة بين 1- و 1.

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

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

تطبيقات عملية

لنلق نظرة على الصورة المتحركة التالية التي تمثل نتيجة جداء خارجي وداخلي لشعاعين ()Vector2.dot و ()Vector2.cross وكيف تتغير كل نتيجة مع تغير الزاوية بين الشعاعين:

06 dot cross

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

كما يساعد الجداء الخارجي في معرفة إن كان الكائن إلى اليسار -عندما تكون قيمة الجداء أكبر من الصفر- أو إلى اليمين -عندما تكون قيمة الجداء أصغر من الصفر-.

الخاتمة

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

ترجمة -وبتصرف- للمقالين: Interpolation و Vectors:Using Dot product and Cross product

اقرأ أيضًا


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

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

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



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

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

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

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


×
×
  • أضف...