بتـــــاريخ : 2/28/2011 8:00:03 PM
الفــــــــئة
  • الحـــــــــــاسب
  • التعليقات المشاهدات التقييمات
    0 1503 0


    درس عن ال vectors (المتجهات) الرجاء المرور و التعليق حتى لو كنت تعرف الموضوع!!

    الناقل : elmasry | العمر :42 | الكاتب الأصلى : hasan_aljudy | المصدر : www.arabteam2000-forum.com

    كلمات مفتاحية  :

    بسم الله الرحمن الرحيم
    في برمجة الالعاب نحتاج الى طرق لتمثيل بعض المفاهيم الفيزيائية مثل الحركة و السرعة و الإزاحة, الخ. في الفيزياء و الرياضيات, نعتمد على المتجهات vectors والاحداثيات coordinates لتمثيل هذه الأشياء. لذلك لا بد من فهم الـ vectors بشكل جيد لكل من يتعلم برمجة الألعاب. أعتذر لأنني لن استطيع شرح الموضوع من الصفر, و لكني افترض ان القارئ يعرف شيئا و لو بسيطا عن المتجهات vectors و لكنه لا يعرف ما فائدتها في برمجة الالعاب او كيف يمكن توظيفها و التعامل معها.
    الـ vectors كما نعرف تمثل اتجاه + طول, عند الكلام ضمن سياق بيئة ثنائية الابعاد فإن الـ vector يتكون من x,y اما في ثلاثة ابعاد فإنه يتكون من x,y,z و كلها ارقام حقيقية real numbers يعني بالـ C++‎ نستخدم float او double و في الـ D نستطيع استخدامهما اضافة الى real.
    ليس للمتجهات vectors علاقة بالمكان, يعني لو رسمنا متجهين لهما نفس الطول و نفس الاتجاه و لكن وضعنا كل منهما في مكان مختلف, فإن كلا الشكلين هما في الحقيقة صورة لنفس المتجه. المتجه يمثل فقط الاتجاه و الطول, فقط. يعني لو احضرت صورتين لشخص معين و علقت واحدة على الحائط ثم وضعت الاخرى على المكتبة, فهذا لن يغير من حقيقة ان الصورتين هما لنفس الشخص. لماذا؟ لان مكان وضع الصورة لا يغير شيئا في ذلك الشخص. نفس الشي مع الـ vectors, المكان ليس له علاقة بتعريف الـ vector على الإطلاق.


    طول المتجه:
    طبعا, لتعريف المتجه, نحتاج لعنصرين, x,y و نحن نفترض هنا اننا نتعامل مع بعدين فقط.
    يمكن حساب طول المتجه بسهولة, اذا عرفنا ان الخط اللذي يمثل المتجه هو في الحقيقة الوتر في المثلث القائم الزاوية, اللذي يبلغ طول ضلعيه الآخرين x و y

    Posted Image

    و بهذا, نكتشف ان طول الـ vector هو sqrt( x*x + y*y )‎ بحسب نظرية فيثاغورس اللتي تدرس في الثانويات.


    تغيير طول المتجه:
    يمكن ضرب المتجه برقم عادي, و في هذه الحالة فإننا في الحقيقة نضرب عناصر المتجه في الرقم, كل على حدة.
    مثلا, المتجه v = (10,13)‎ لو ضربناه في 2 سوف نحصل على v = (20, 26)‎.
    حين نضرب المتجه بـ 2 فإننا في الحقيقة نضاعف من طوله, و حين نضربه في 3 فإن طوله يصبح ثلاث مرات بحجم الطول السابق. و حين نضربه في نصف (1/2) فإننا نحول طوله الى نصف ما كان عليه. يعني ضرب المتجه يؤدي بالنتيجة الى تغيير طوله بحسب عامل الضرب.
    لو ضربت المتجه في الرقم factor فإن الطول الجديد سيصبح الطول القديم مضروب في factor ...
    newLength == oldLength * factor



    عمل normalization للمتجه:
    احيانا نحتاج الى تحويل طول المتجه الى 1, و لكي نفعل ذلك نضرب المتجه في المعكوس الضربي لطوله, يعني ‎(1/length)‎. ارجو ان تفكروا في الموضوع قليلا. اذا كان عامل الضرب هو نفس الطول, فإن الطول الجديد سيكون length/length و هذا يساوي 1.


    الفرق بين نقطتين:
    تخيل اي نقطتين p و q على المستوي (on the plane), اذا انتقل شيء ما من p إلى q فإننا نستطيع تمثيل الازاحة عن طريق رسم متجه يبدأ في p و ينتهي عند q. يمكن حساب المتجه عن طريق v = q – p اي:
    v.x = q.x – p.x
    v.y = q.y – p.y
    كيف يحدث ذلك؟



    العلاقة بين النقاط (الاحداثيات) و المتجهات:
    كل من النقاط و المتجهات points and vectors يتم تمثيلها عن طريق x,y فما الفرق بينها؟
    الفرق هو ما تعنيه و ما نقصده منها. النقاط تمثل احداثيات مكان معين, بينما المتجهات تمثل اتجاها معينا و طولا.
    هناك عمليات رياضية قد تشمل النقاط و المتجهات معا, كما رأينا قبل قليل اننا اذا طرحنا نقطتين من بعض, فإننا سنحصل على متجه يمثل مقدار الإزاحة, و لكن هذا المتجه لا يخبرنا اين حصلت الإزاحة, فقط يخبرنا اتجاهها و ما هي المسافة اللتي حصلت بها.


    الإزاحة:
    الازاحة هي تحرك كائن او ازاحته من نقطة الى أخرى. اذا كان لدينا كائن يقبع في النقطة a ثم تمت ازاحته بمقدار d فإن مكانه الجديد هو n حيث:
    n.x = a.x + b.x
    n.y = a.y * b.y
    بمعنى آخر, اضفنا عناصر x,y في النقطة الى عناصر x,y في المتجه اللذي يمثل الإزاحة, و هكذا حصلنا على المكان الجديد للكائن.



    تمثيل السرعة كمتجه:
    يمكن تمثيل السرعة كمتجه, كيف ذلك؟
    اعتذر عن سوء استخدام المصطلحات العربية في هذا الشأن, على كل حال, هناك نوعين من السرعة في الرياضيات: speed و velocity, كلاهما تعنيان في اللغة "السرعة" و لكن اصطلاحا, فالمعنيان مختلفان جدا. الـ speed هي مقدار السرعة من دون اتجاه .. مثلا .. سيارة تتحرك بسرعة 50 كيلو متر في الساعة. هذه سرعة من دون اتجاه .. يعني speed.
    اما الـ velocity فإنه لتعريفها نحتاج السرعة اضافة الى اتجاه الحركة, يعني لا يكفي ان تقول ان السيارة تتحرك بسرعة 50 كيلو متر في الساعة, بل يجب ان تحدد اتجاهها, مثلا 30 درجة مئوية الى الشمال من الشرق. في هذه الحالة فقط عرفنا الـ velocity.
    يمكننا تعريف الـ velocity عن طريق متجه x,y حيث ان اتجاه المتجه سيعتبر اتجاه الحركة, و طول المتجه يعتبر كمية او مقدار السرعة.
    طيب لنفرض ان هناك vector يمثل الـ velocity و ان طول هذا المتجه هو 12, فماذا يعني هذا؟ هل هي 12 كيلو متر في الساعة؟ ام هي 12 متر في الثانية؟ ام 12 متر في الدقيقة؟ ام ماذا بالضبط؟!! للاجابة على هذا السؤال, فإن الوحدة اللتي تقيس بها الزمن و المسافة ليس لها علاقة بالمتجه.
    تذكروا ان المتجه هو كائن رياضي, مثله مثل الرقم. لو قلت ان سرعة السيارة هي 10, فهل هذه المعلومات تخبرك ما هي السرعة بالضبط؟ انها فقط تخبرك ان سرعة السيارة هي 10 وحدة مسافة لكل وحدة زمن, لكن ماهية وحدات المسافة و الزمن ليست جزء من الرقم "10".
    نفس الشيء بالنسبة للمتجهات, ماهية وحدات المسافة و الزمن ليست جزء من المتجه.
    حتى عندما نتعامل مع النقاط و الاحداثيات .. نحن نعرف ان المسافة بين النقطة 0,0 و النقطة 0,1 هي 1, و لكن 1 ماذا؟ هي هل متر واحد؟ ام سنتيمتر واحد؟ ام ميل واحد؟ ام ماذا؟!!
    هي ليست اي من ذلك, بل قد تكون اي شيء .. و لكن نحن ندرس الموضوع بتجريد, يعني نقول "وحدة مسافة واحدة" دون تحديد ما هي هذه الوحدة. و لكن حين نطبق هذه الأشياء على امثلة واقعية, يجب ان نتعامل مع وحدات حقيقية. و لكن لغرض الدراسة النظرية, نكتفي بالقول "وحدة مسافة" و "وحدة زمن".


    تحريك كائن من نقطة معينة عن طريق سرعته:
    لنفرض ان هناك كائن, و لتكن سيارة, متواجدة في النقطة 10,3 و تتحرك بسرعة 2,4
    ما هو مكان هذه النقطة بعد وحدة واحدة من الزمن؟
    في الحقيقة هناك شيء لم اقله قبل قليل, و هو ان تعريف السرعة على انه 2,4 يعني ان الكائن يتم ازاحته بمقدار 2,4 في كل وحدة من الزمن.
    فبعد وحدة واحدة من الزمن, فإن السيارة محل السؤال, قد تعرضت لازاحة مقدارها 2,4 و بناءا على ذلك فموقعها الجديد هو ‎10+2,3+4‎ و هذا يساوي 12,7
    و بشكل عام, فإن لو كان لدينا كائن موجود في لحظة معينة في النقطة p و يتحرك بسرعة v فإن موقعه بعد وحدة واحدة من الزمن سيكون q حيث:
    q.x = p.x + v.x
    q.y = p.y + v.y
    اما بعد وحدة غير معينة من الزمن, و لتكن t, فالأمر مختلف قليلا, حيث اننا نضرب متجه السرعة في الرقم t لنحصل على مقدار الإزاحة بعد t وحدات من الزمن.
    q.x = p.x + (v.x * t)‎
    q.y = p.y + (v.y * t)‎
    العمليات الرياضية اللتي اجريناها:
    حتى الآن, اجرينا عدة انواع من العمليات الرياضية على المتجهات و النقاط:
    - ضرب متجه في عدد
    - اضافة متجه الى نقطة
    - طرح نقطة من نقطة
    و قد وضحت ان الجمع و الطرح بين النقاط و المتجهات يتم بجمع كل من المكونات x,y على حدة, اما الضرب فيتم بضرب كل من x,y بالعامل على حدة.


    تطبيق ما سبق في لعبة:
    نستطيع الان ان نقوم بتطبيق بسيط, يحتوي على كائن معين, يبدأ من نقطة معينة, ثم ياخذ سرعة معينة, ثم يبدأ بالتحرك بحسب هذه السرعة او الـ velocity و حين يخرج خارج الشاشة نقوم بحذفه و تحرير الذاكرة اللتي كان يشغلها.


    شرح نظري:
    نقوم بإنشاء الكائن و الاحتفاظ بمؤشر له في مكان ما, و في الـ game loop نقوم بتسجيل الوقت باستمرار و استدعاء method معين لتحديث الكائن ذاك, حيث نقوم فيه بحساب الفرق بين الوقت الحالي و بين الوقت السابق, اي عند المرة السابقة اللتي استدعينا فيها نفس الـ method, و لنسمه update. بعد ان عرفنا الفرق في الوقت, نقوم باخذ سرعة الكائن و ضربها في فرق الزمن, و بذلك نحصل على مقدار الازاحة اللتي كان يجب ان يتحركها الكائن في تلك المدة. ثم نقوم باضافة هذه الازاحة الى مكان الكائن الحالي من اجل ان نحركه بالفعل الى المكان الذي يجب ان يكون فيه.
    بعد ذلك, نقوم بفحص مكان الكائن, و اذا وجدنا انه خارج حدود الشاشة, نقوم بحذفه من الذاكرة.
    بعد ذلك, نقوم برسم الكائن في المكان المحدد.


    كود عام:
    اليكم pseudo code للنظرية اعلاه:

    GameObject * object;
    double currentTime;
    double prevTime;
    double timeDelta;

    void init()
    {
            object = null;
            currentTime = getTime();
            prevTime = getTime();
            timeDelta = 0;
    }

    void gameLoop()
    {
            prevTime = currentTime; //store previous time
            currentTime = getTime(); //update current time
           
            timeDetla = currentTime - prevTime;
           
            processUserInput(); //get input from the keyboard/mouse/whatever
           
            if( object != null )
            {
                    updateObject( object, timeDelta );
                    if( outsideScreen( object ) )
                    {
                            delete object;
                            object = null;
                    }
                    else
                    {
                            render( object );
                    }
            }      
    }

    void updateObject( GameObject * obj, double time )
    {
            obj.position = obj.position + (obj.velocity * time);
    }




    برمجة كلاس للمتجهات و النقاط:
    في الـ pseudo code استخدمت عمليات على السرعة و المكان دون تعريف كيف تم ذلك .. و اقصد الدالة updateObject, إذن, لنرى كيف يمكن كتابة الكلاس. المسألة بسيطة جدا اذا طبقنا الشرح النظري عن المتجهات.
    struct Vector
    {
            real x;
            real y;
           
            void add( Vector v )
            {
                    x += v.x;
                    y += v.y;
            }
           
            void sub( Vector v )
            {
                    x -= v.x;
                    y -= v.y;
            }
           
            void multiply( real factor )
            {
                    x *= factor;
                    y *= factor;
            }
           
            real length()
            {
                    return sqrt( x*x + y*y );
            }
    }


    هذا هو الهيكل العظمي .. و قد استخدمت struct بدل class, لا توجد مشكلة كبيرة. كما اني لم اقم بعمل operator overloading


    تكملة المثال:

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



    في الختام:
    ارجوا التعليق على الموضوع, و هل تعتقدون انه جيد ام لا؟ احب ان اسمع اراء الناس اللذين لم يكونوا يفهموا الـ vectors, و اريد ان اعرف, هل يشعرون انهم يفهمونها اكثر الان؟ ما هي الاشياء الناقصة في الموضوع؟ كيف يمكن تحسينه؟!

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

    كلمات مفتاحية  :

    تعليقات الزوار ()