بتـــــاريخ : 2/26/2011 8:42:12 PM
الفــــــــئة
  • الحـــــــــــاسب
  • التعليقات المشاهدات التقييمات
    0 1142 0


    تحريك الأجسام في اللعبة نظرية و تطبيق بسيط

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

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

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

    في هذا الموضوع سنستخدم freeglut كما تحدثنا في الموضوع السابق, و الأفضل قراءة المواضيع السابقة قبل قراءة هذا الموضوع.
    الرسم على الشاشة و opengl
    حجر الأساس في برمجة الألعاب: الـ Game Loop
    freeglut

    ما اريد التحدث عنه اليوم هو تحريك الكائنات في اللعبة ..
    لنحلل المسألة قبل الشروع في العمل:
    و لنأخذ أبسط حالة: لدينا كائن واحد, نرسمه على شكل مربع, و نضعه في بداية اللعبة في مكان ما على الشاشة.
    (هنا أنوه انك لا بد ان تكون فاهما جيدا لمسألة ان الشاشة هي عبارة عن سطح ثنائي الأبعاد, مكون من مجموعة كبيرة من النقاط المتراصة, و لنرسم شيئا على الشاشة علينا ان نحدد موقعه.)
    السؤال هو, كيف نحرك هذا الكائن؟
    حسنا, لنفرض اننا كبداية, رسمنا الكائن هذا في موقع x,y = 100,80
    و نريد تحريكه الى اليمين, كيف؟
    لا بد ان نعرف أولا الـ coordinate system المستخدم في نظام الرسم .. في الـ opengl عادة تكون نقطة الصفر هي النقطة السفلية اليسرى .. بناءا على ذلك, كلما ازدادت قيمة x سنتحرك باتجاه اليمين, و كلما نقصت قيمة x سنتحرك باتجاه اليسار.
    و بنفس المنطق, كلما زادت قيمة الـ y تحركنا الى الأعلى, و كلما نقصت قيمة الـ y تحركنا الى الأسفل.

    إذا, لو اردنا تحريك هذا الكائن خطوة واحدة الى اليمين, يجب ان نمسحه من موقعه القديم و نرسمه في الموقع الجديد و هو x,y = 101,80
    قد يكون هذا المقدار ضئيلا جدا بحيث ان المستخدم قد لا يلاحظ فرق .. لذلك يمكن زيادة الازاحة حسب الرغبة.

    من أجل ان نقوم بذلك في البرنامج, يجب علينا ان "نتذكر" الموقع الحالي للكائن, بحيث كلما نحركه نمسحه من موقعه القديم, نغير قيم x,y حسب المطلوب, ثم نرسمه من جديد على الموقع x,y بعد ان تغير ليعكس الموقع الجديد المفترض للكائن.

    عملية المحو من الموقع القديم يمكن عملها في opengl عن طريق محو الشاشة بكاملها! باستخدام glClear
    مسألة اخذ input من الـ keyboard في glut معقدة شوية .. لازم نسجل callback function للـ event اللذي يحدث عن ضغط زر على الكيبورد .. لاحظوا الكود.

    مسألة رسم مربع, مسألة بسيطة نسبيا .. يمكن رسم مربع عن طريق البدء بـ glBegin و نمرر لها GL_POLYGON ثم نحدد نقاط المربع ثم نستدعي glEnd, النقطة الوحيدة اللتي يجب الانتباه لها هي ترتيب النقاط .. لازم نرسلها بترتيب معين و الا يتخربط الشكل. (لو مش واضحة هالنقطة ممكن نوضحها أكثر إن شاء الله حسب رغبتكم).

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

    هذا تطبيق مع بعض التعليقات البسيطة.

    #include <windows.h>
    #include <GL/glut.h>

    int x, y; //global variables for the location of the object
    void drawBox( int x, int y ); //a function to draw a small box at a certain location
    void handleInput( int key, int mx, int my ); //our keyboard event handler
    void init();

    int main(int argc, char** argv)
    {
       glutInit(&argc,argv);
       glutInitDisplayMode(GLUT_SINGLE |GLUT_RGB);
       glutInitWindowSize(400,400);
       glutInitWindowPosition(50,50);
       glutCreateWindow("Moving Box");
       glutSpecialFunc( handleInput ); //register our keyboard handler for special keys (arrows are special keys)
       init(); //initialize
       glutMainLoop(); //enter the glut main loop ..
       return 0;
    }

    void drawBox( int x, int y )
    {
        int x1 = x + 20;
        int y1 = y + 20;

        glBegin(GL_POLYGON);
            //note the order of sending the points, it's important
            glVertex2d( x, y );
            glVertex2d( x, y1 );
            glVertex2d( x1, y1 );
            glVertex2d( x1, y );
        glEnd();
    }

    void handleInput( int key, int mx, int my )
    {
        //if key is an arrow key, adjust the global x,y accordingly
        switch( key )
        {
        case GLUT_KEY_LEFT:
            {
                x -= 5;
            }
            break;
        case GLUT_KEY_RIGHT:
            {
                x += 5;
            }
            break;
        case GLUT_KEY_UP:
            {
                y += 5;
            }
            break;
        case GLUT_KEY_DOWN:
            {
                y -= 5;
            }
            break;
        default:
            return; //if it's not an arrow key, we can quit the function
        }

        //clear the screen and draw the box in it's new position
        glClear(GL_COLOR_BUFFER_BIT);
        drawBox( x, y );
        glFlush();
    }

    //Typical initialization function .. not how ever that we initlize the object too.
    void init()
    {
       glClearColor(0.3f,0.3f,0.3f,0.0f);
       glColor3f(1.0,1.0,0.5);
       glPointSize(2.0);
       glMatrixMode(GL_PROJECTION);
       gluOrtho2D(0.0,768.0,0.0,1024.0);
       
       //initialize and draw the object in its initial location
       x = y = 30;
       glClear(GL_COLOR_BUFFER_BIT);  
       drawBox( x, y );
       glFlush();
    }





    هنا لا بد لنا من ملاحظة مهمة: عملية تحريك الكائن مكونة من خطوتين: الأولى تغيير المتغيرات x,y لكي نمثل الموقع الجديد للكائن, و الخطوة الثانية هي رسم الكائن في الموقع x,y بعد ان غيرناه.
    في هذا المثال فإن كلا الخطوتين حصلتا في نفس الـ function و بشكل متتابع مباشرة. و لكن في الالعاب الكبيرة عادة نقوم بتغيير الـ x,y في مكان ما من الكود .. و نقوم بعملية الرسم في مكان آخر من الكود بعيد تماما عن المكان اللذي غيرنا في الـ x,y (عندما اقول "مكان" هنا .. فأنا اقصد مكان في الكود ..مثلا في الملف الفلاني في الدالة الفلانية في السطر الفلاني)

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

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