جميع الحقوق محفوظة لموقع ALGameDev.com ولمؤلف هذه المقالة..المقالة موجهة للهواة ولانضمن صحتها الكاملة


بلوحة مفاتيح: عبدالله الشمري

الصفحة الرئيسية

الدرس الأول : مفاهيم أساسية تحتاجها .

ALGamedev.Com

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

بعد أن نجحنا في تثبيت OpenGL ( يعني LWJGL ) , ونفذنا تطبيق تجريبي , وظهرت لنا نافذة فارغة , فان هذا انجاز بحد ذاته , لذلك افخر بنفسك . سنشرح مفاهيم أساسية في برمجة الألعاب بشكل عام و في OpenGL بشكل خاص , معظم ما سأكتبه هو ليس دقيق 100% , لكن سيكون ذلك من أجل ايضاح المفاهيم .

أولا : ربط OpenGL بالنظام .. بالجافا .. :

هذا عبارة عن تكتنيك ( أكثر مما هو مفهوم ) ..
OpenGL كالذباب الصغير.. تقع على كل شيء تراه أمامها ..لذلك هي لا تعرف أين تشتغل , ولايهمها ذلك , بل مهمتها أن تعمل . OpenGL تتصل بالنظام عن طريق أوامر هذا النظام Linux - windows - Mac الخ ..في الويندوز تستعين OpenGL بدوال النظام Win32 API .
كذلك OpenGL ممكن ترسم على النافذة , أو ممكن ترسم الى صورة ( مثل برامج الاوتوكاد ) . لذلك شيء طبيعي أن يكون برنامجك الأول في OpenGL مختلف من نظام لاخر ومن لغة لاخرى ومن مكتبة لاخرى .
غالبا الخطوات التي سنقوم بتنفيذها هي كالتالي :
  • انشاء نافذة + تحديد أبعادها + تحديد دقة الشاشة وأمور أخرى .
  • توفير نظام ادخال input من لوحة المفاتيح مثلا + توفير بعض الاحداث الاساسية مثل تغيير حجم النافذة.
  • نحن نستخدم مكتبة LWJGL ( أعلم أنك تعلم ! ) .. والفئة أو الصنف أو الكلاس المسؤول عن ربط OpenGL بالجافا ( وبالتالي بالنظام ) هو Device , سترى كيف يتم ذلك .

    ثانيا: نظام الاحداثيات في OpenGL ( الاسقاط ) :

    OpenGL تعتمد على المصفوفات في عملها ( مصفوفة 4*4 كما درست في المدرسة ) .. والمصفوفة المسؤولة عن عمليه الاسقاط (Projection ) هي Projection_Matrix ... ماذا نعني باسقاط .. مصفوفة .. حسنا .. اترك كل هذا .. لاننا سنرى كيف يتم ذلك لاحقا ان شاء الله .
    المهم : الاسقاط نوعان :
  • orthographic ( الاسقاط العمودي): غالبا نستخدمه مع ألعاب ثنائية البعد .
  • perspective ( الاسقاط المنظوري) : غالبا مع ألعاب ثلاثية البعد .
  • في كلا الحالتين .. أنت تستطيع أن تتحكم بنظام الاحداثيات بسهولة .. وسنتكلم أيضا عن هذا الموضوع لاحقا .. لكن مايهمنا الان هو معرفة النظام الافتراضي الذي تقدمه لنا المكتبة LWJGL .
  • الاسقاط هو عمودي ( ortho ) .
  • نقطة الاصل هي الزاوية اليسرى السفلية من النافذة .. و عرض النافذة يمثل آخر نقطة يمين النافذة .. وطول النافذة يمثل آخر نقطة أعلى النافذة .
  • ALGamedev.Com

    فلو كان عرض النافذة 200 وطولها 100 .. فان الاحداثيات هي كالتالي :

    ALGamedev.Com

    ثالثا: loop ومبدأ حفظ الرسم .

    بعد أن ربطت OpenGL بالجافا و بعد أن تعرفت على نظام الاحداثيات .. ستقوم بالرسم . ستحتاج الى أن تحتفظ بالرسم موجودا على النافذة تطبيقا لمبدأ هام وهو اعادة الرسم . في برمجة الألعاب بشكل عام , استخدام الحلقة التكرارية loop هي أهم أركان أي لعبة , فبرنامجك يظل يدور ويدور ويدور حتى تخرج من اللعبة .. ومادمت تدور فانك تقوم بالمهام التالية :
  • استقبال الرسائل من النظام أو من الكيبورد .. الخ .
  • تحديث الاحداثيات .. الذكاء الاصطناعي .. الفيزياء .
  • رسم المجسمات على النافذة .
  • هكذا :
    bool finish = false;
    while ( finish == false)
    {
       //     processInput
    
         if( Input.getKeyDown() == VK_ESCAPE )
                finish = true ;
    
         updatePosition();
    
         draw3DShape();
    
    }
    
    وبالتالي ستظل رسوماتك و معالجاتك للبيانات قائمة .. مادامت اللعبة في حالة التشغيل .

    رابعا : مفهوم الBuffers في OpenGL .

    تعتمد OpenGL في عملها على عدة أنوان من ال Buffers .. أولا ماهو ال Buffer ..؟
    هو عبارة عن كتلة من الذاكرة المحجوزة التي تخزن فيه البيانات .. يعني OpenGL تحجز جزء من الذاكرة لتخزن فيها المعلومات ..والمعلومات أنواع :
  • Color Buffer :
  • وهو النوع الهام .. والذي لن تستغني عنه.. هذا البفر Buffer يخزن الالوان .. هل رأيت الالوان التي تظهر على نافذتك عن تشغيل OpenGL .. هذه عبارةعن مجموعة من الألوان ..و بالتالي هي عبارة عن مجموعة من البايتات ..جميع الرسوم يتم تخزينها على شكل " بكسلات " في هذا ال Buffer .
  • Depth Buffer
  • وهو يخزن معلومات تخص كل بكسل .. بحيث يظهر هذا البكسل في عالم ثلاثي الابعاد .. اذا فائدة هذا ال Buffer هو في التطبيقات الثلاثية البعد ..عموما .. لافائدة من الحديث عن هذه ال Buffers بدون تطبيق .. لذلك سنتكلم عنها لاحقا , المهم الان هو Color Buffer
    كما قلنا قبل قليل .. اللعبة تحوي على loop .. في كل loop يجب أن نمسح Color Buffer قبل أن نرسم فيه .
  • نسمح Color Buffer .
  • نرسم نقطة خضراء .
  • نرسم نقطة زرقاء .
  • نظهر الرسمه النهائية .
  • نعود لمسح Color Buffer .. وهكذا .
  • لانه من غير المنطقي .. في كل loop ترسم على ما رسمت سابقا .. عندها .. ستظهر عندك عشرات النقاط الحمراء بدلا من نقطة واحدة لانك في كل مرة لاتمسح Color Buffer .. من المخلفات .. أمر المسح هو :
    glClear(GL11.GL_COLOR_BUFFER_BIT )
    

    خامسا : مفهوم Double Buffer :

    كما قلنا سابقا ... في كل بداية loop يجب مسح Color Buffer من أي مخلفات سابقة قبل أن نرسم عليه .. لكن هنا تولدت مشكلة .. كل مرة نمسح Color Buffer .. ونرسم من جديد ) للتحديث) .. فان الرسم " يرمش" بشكل مزعج .. لأننا نمسح ونرسم أما مرأى ومسمع المستخدم .. ( لاتنسى ان عملية المسح مكلفة وليست بسيطة ) .. لذلك الحل هو .. أن نمسح ثم نرسم في سطح خلفي Back Buffer ثم اذا انتهينا من هذه العملية .. نجلب هذا السطح الخلفي الى السطح الامامي Front Buffer .. وعملية الجلب تسمى بالSwap Buffer أو Update .

    ALGamedev.Com

    نستخدم الدالة update الموجودة في الكلاس Device لعمل swap buffer .

    مثال :

    اخيرا وصلنا للمثال .. هو نفس مثالنا السابق .. لكن هنا مع الشرح :) ..
    
    /*
     * الهدف الاساسي من هذا المثال هو تنفيذ برنامج بسيط
     * بنافذة فارغة .. واستقبال بعض الأوامر من الكيبورد
     * فهم اسلوب ومنهج الالعاب
     */
    
    import org.lwjgl.input.Keyboard;
    import org.lwjgl.opengl.*;
    import org.lwjgl.opengl.GL11;
    
    public class OpenGL_01 {
    
      public static void main(String[] args) {
    
    //------------------------- Init + Create Frame (Firstly) --------------------------
       Display.setTitle( "My Game");
    
       try
       {
           Display.setDisplayMode(new DisplayMode(400, 400));
       }
       catch(Exception a)
       {
           System.out.println(a);
    
       }
    
       try
        {
        Display.setFullscreen(false);
        }
       catch(Exception e)
        {
            System.out.println(e);
    
        }
    
       try
        {
        Display.create();
        }
       catch(Exception e2)
        {
            System.out.println(e2);
        }
    
     //------------------------- Render + Input (Processing )  --------------------------
       boolean finished = false;
    
        while (!finished) {
    
          // Check for close requests
          if (Display.isCloseRequested()) {
    	finished = true;
          }
    
            if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE))
                  finished = true;
    
    
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT );
    
       // Draw Here ...
    
    
        Display.update();
    
    
        }
     //------------------------- Release ( Finally )  --------------------------
        Display.destroy();
        System.exit(0);
      }
    
    
    }
    
  • لاحظ أن جميع دوال OpenGL للنسخة رقم 1.1 موجودة في الكلاس GL11 والدوال الخاصة بالنسخة رقم 1.2 موجودة في الكلاس GL12 الخ ..
  • ننشى النافذة عن طريق
    Display.setDisplayMode(new DisplayMode(400, 400));
    
    التي تطلب كلاس يحدد لنا أبعاد النافذة ..
  • setFullscreen .. من خلالها نستطيع الانتقال من والى وضع ملء الشاشة .
  • لاحظ طريقة استقبالنا للمدخلات من المستخدم وذلك عن طريق الكلاس Keyboard .
  • لاحظ أنه في داخل الloop يوجد ثلاث عمليات أساسية .. مسح الشاشة ثم رسم ثم تحديث ال buffer أي جلب البيانات من السطح الخلفي الى السطح الأمامي ... ( طبعا لم نرسم شيء الان ) .
  • النتيجة هي نافذة سوداء .. كالحة .. درس ممل لكن مهم .. وتعتمد عليه جميع الدروس القادمة .


    الصفحة الرئيسية