Skip to content
This repository has been archived by the owner on Sep 18, 2024. It is now read-only.

Latest commit

 

History

History
382 lines (256 loc) · 14.8 KB

File metadata and controls

382 lines (256 loc) · 14.8 KB

السلام عليكم ورحمة الله وبركاته

--{تحسين الحركة}--

الدرس الحادي عشر - 11

في الدرس السابق كتبنا اوامر الحركة الاساسية في الجهات الاربعة
وكان امر الحركة الى اليمين كهذا

var speed = 300

func _physics_process(delta):
    # Move Right
    if Input.is_action_pressed("ui_right"):
        position.x += speed * delta

هل يمكننا تحسينه ؟

بالطبع يمكننا، لقد عرفنا ان Input.is_action_pressed("ui_right") دالة ترجع لنا قيمة boolean تكون true اذا ضغط المستخدم على زر السهم الايمن في لوحة المفاتيح وfalse ان لم يضغط، حسنا مادام انها قيمة boolean فيمكننا تخزينها في متغير، شيء مثل هذا

var speed = 300

func _physics_process(delta):
    var right := Input.is_action_pressed("ui_right")

    # Move Right
    if right:
        position.x += speed * delta

خزنا القيمة في متغير يدعى right ثم استخدمناهُ في الشرط، المتغير اصبح يصف وظيفته
قد تظن ان هذا الامر تافه في بادئ الأمر لكن دعنا نرى الاوامر مع باقي الاتجاهات

var speed = 300

func _physics_process(delta):
    # Define the input
    var right := Input.is_action_pressed("ui_right")
    var left := Input.is_action_pressed("ui_left")
    var up := Input.is_action_pressed("ui_up")
    var down := Input.is_action_pressed("ui_down")

    # Movement
    if right:
        position.x += speed * delta

    if left:
        position.x -= speed * delta
    
    if up:
        position.y -= speed * delta

    if down:
        position.y += speed * delta

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

يمكننا ان نجعل الحركة افضل من هذا، دعونا نرى المتغيرات التى تحدد الاتجاهات

    var right := Input.is_action_pressed("ui_right")
    var left := Input.is_action_pressed("ui_left")
    var up := Input.is_action_pressed("ui_up")
    var down := Input.is_action_pressed("ui_down")

حسنا نحن نعرف ان الاتجاه الى اليمين تكون قيمة ال x موجبة واليسار تكون قيمة ال x سالب
الان قيمة كل متغير ستكون true اذا تم ضغط على الزر الذي يشير اليه و false اذا لم يضغط

اذا ماذا سيحدث اذا طرحنا اليسار من اليمين ؟

    var right := Input.is_action_pressed("ui_right")
    var left := Input.is_action_pressed("ui_left")
    
    var directionX := int(right) - int(left)

حسنا هنا اذا تحرك اللاعب الى اليمين فقط، ستكون قيمة ال right ب true و قيمة ال left ب false فهكذا عملية الطرح ستكون هكذا
int(true) - int(false)
لكن هنا لا يمكننا عمل معادلات كالضرب والجمع والطرح على انواع boolean فيجب تحويلها الى int ثم نقوم بعملية الطرح

عند التحويل نضع القيمة داخل int(value) هكذا قيمة ال value ستتحول الى int مهما كانت فستكون
int(true) = 1 و int(false) = 0

    var directionX := int(right) - int(left)
    # directionX = 1 - 0 is 1

بالتالي اذا تحرك اللاعب نحو اليمين ستكون قيمة directionX تساوي 1، واذا تحرك نحو اليسار ؟ ستكون 1-

    var directionX := int(right) - int(left)
    # directionX = 0 - 1 is -1

بالتالي اصبح لدينا متغير قيمتة تكون ب 1 حين يتحرك اللاعب لليمين و1- حين يتحرك لليسار وإذا لم يضغط على اي اتجاه ستكون قيمته ب 0

دعونا نرى كيف سيكون أمر الحركة الأن
قبل هذا، انوه اننا سنختصر الأمر الى هذا

    var directionX := int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))

بدلًا من هذا

    var right := Input.is_action_pressed("ui_right")
    var left := Input.is_action_pressed("ui_left")
    
    var directionX := int(right) - int(left)
لا فرق كبير بين الأمران، فقط وفرنا متغيرين

حسنا الان سنكتب كيف سيكون أمر الحركة في اتجاه اليمين واليسار الان

    var directionX := int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))

    if directionX:
        position.x += directionX * speed * delta

اصبح الان لدينا متغير واحد يحدد اتجاه الحركة في اليمين واليسار

أنستطيع فعل نفس الشيء مع الحركة في الاتجاهين الاسفل والاعلى ؟

بالطبع !

    var directionY := int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up"))
    
    if directionY:
        position.y += directionY * speed * delta

اصبح لدينا متغير اخر وهو directionY يحدد الاتجاه لأعلى ولأسفل
اذا كان قيمته 1 يكون الاتجاه لأسفل واذا كانت 1- يكون الاتجاه لأعلى لان محور y معكوس في محرك غودوت

سيكون أوامر الحركة كالأتي

    var directionX := int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))
    var directionY := int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up"))
    
    if directionX:
        position.x += directionX * speed * delta

    if directionY:
        position.y += directionY * speed * delta

حسنا انظر الأن لدينا متغيرين الاول يمثل اتجاه الحركة في محور ال x والمتغير التاني يحدد اتجاه الحركة في محور y
ماذا لو دمجنا هذين رالمتغيرين في متغير واحدة يحدد اتجاه الحركة ؟

نستطيع فعل هذا باستخدام نوع البيانات Vector2
فنحن نعرف ان من خواصه انه يحتوي على متغيرين في داخله x, y نستطيع الوصول لهما والتعديل عليهما وتخزين القيم فيهما

var speed = 500
var direction : Vector2

func _physics_process(delta):
    direction.x = int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))
    direction.y = int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up"))

    if direction:
        position += direction * speed * delta

لم يختلف الأمر كثيرة، حتى ان الشرط اصبح واحد
if direction اي طالما ان هناك حركة اي طالما ان قيمتي ال x,y في ال direction كلايهما لا يساويان 0 نفذ الأمر التالي
position += direction * speed * delta

مشكلة في الزوايا

دعونا نلقى نظرة على تحركات اللاعب بشكل عملي

سنلاحظ مشكلة مزعجة وهي ان التحركات في الزواية تكون اسرع بكثير
اي اذا تحرك اللاعب في اليمين مع الاسفل في نفس الوقت فان سرعته في اتجاه الجنوب الشرقي سيكون اسرع من الطبيعي

ولكي نفسر الامر انظر الى الصور التالية

هنا عندما يتحرك اللاعب في اتجاه اليمين فقط يكون محور x يساوي 1 ومحور y يساوي 0

position += direction * speed * delta
الأمر هنا كانك تقول له (1, 0) * speed
حيث ان (1, 0) هو متجه اتجاه ناحية اليمين طوله 1

وان حسبنا طوله عن طريق ايجاد الحد المطلق للمتجه

سيعطينا 1 وهو ما سينضرب في ال سرعة speed بالتالي السرعة لن تتغير اي ستظل كما هي، فقط الاتجاه من له عامل التاثر هنا وهذا ما نريده

وعندما يتحرك نحو الاسفل يصبح y يساوي 1 و x يساوي 0
سيكون نفس الأمر كانك تقول له (0, 1) * speed
حيث ان (0, 1) هو متجه اتجاه ناحية الأسفل طوله 1

والحسبة ستعطينا نفس النتيجة

أين المشكلة ؟

اذا تحرك ناحية اليمين والاسفل في ان واحد يصبح x وy كلايهما يساويان 1 وهنا تظهر المشكلة
بحيث ان المتجه (1, 1) ان حسبت قيمته او طوله

سيعطيك اي 1.4142 وهكذا سيزيد سرعة اللاعب عن المتوقع وهكذا اصبح المتجه يؤثر على السرعة وهذا ما لا نريده
نحن نريده ان يحدد لنا الاتجاه فقط لذا يجب على طوله ان يكون مساويًا ل 1 لكي لا يؤثر على السرعة

position += direction * speed * delta
هنا سيتجه اللاعب ناحية الجنوب الشرقي لكن السرعة speed ستزيد على الطبيعي لانها سيتم ضربها في 1.4142 وليس 1

Normalization Function

حل هذه المشكلة سيكون بعمل بعض المعادلات الخاصة على المتجه ال direction
نرجع لمثالنا الاول وهو اذا تحرك اللاعب ناحية اليمين والاسفل في ان واحد يصبح direction يساوي (1, 1)
وهذا ما يجعل طوله اي الوتر يكون 1.4142 كما وضحنا

اذا نحن نريد ان نغير قيم ال x و y الخاصة بال direction ليكون طوله 1
اي اننا سنحول متجه ال direction الى متجه الوحدة وهذا هو مفهوم ال Normalization

كيف يتم تحويل المتجه الى متجه الوحدة

ال normalization يحول اي متجه الى متجه وحدة، لكن كيف ؟
عن طريق بعض المعادلات البسيطة، وهي كالأتي ان كان لديك متجه قيمه (3, 4) وان اردت ايجاد طوله سيكون 5

لنحوله الى متجه الوحدة كل ما علينا فعله هو ان نقسم قيم المتجه على طوله اي الوتر والوتر يقسم ايضا في نفسه
فسوف نقسم قيم xو y والوتر على 5، كما هو موضح في الصورة التالية
هكذا سيصبح طول المتجه اي الوتر يساوي 1 وقيم xو y سيتغيران ليتناسبا مع ناتج الوتر

في غودوت لدينا دالة متواجدة داخل خواص Vector2 تدعى normalized تحول المتجه الى متجه الوحدة
نحن نعرف ان المتغير direction من نوع Vector2 فنستطيع استدعاء دالة ال normalized

direction.normalized()

لكن دالة normalized لا تعدل في قيم المتجه direction ذاتها
لذا ان كتبته كهذا لن يحدث اي تغير في قيم direction

لانها ترجع قيمة ال direction بعد ان تحول الى متجه الوحدة لذا يجب ان نستقبلها في نفسها بهذا الشكل

direction = direction.normalized()

لذا فإن حل مشكلة الحركة في الزوايا يكون باستعمالها

وهذا توضيع عملي للأمر

ستلاحظ سرعة اللاعب في الزوايا تقل عند استخدامنا لدالى ال normalized ونحن نطبع طول المتجه قبل وبعد استخدام الدالة لتلاحظ الفرق

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

أوامر الحركة بشكل كامل

extends KinematicBody2D

var speed = 500
var direction : Vector2

func _physics_process(delta):
    # define direction of movement
    direction.x = int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))
    direction.y = int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up"))
    
    # make a vector transform into the unit vector
    # i.e. its length equals 1
    direction = direction.normalized()
    
    # Movement
    if direction:
        position += direction * speed * delta