بسم الله الرحمن الرحيم
احب ان اشارك اخواني في اثراء القسم و سوف اتكلم في هذه الدورة عن طرق تنظيم الكود و ادارة الالعاب سوف يكون تطبيق الدورة على
لغة البرمجة C++ و مكتبة OpenGL و المكتبة GLUT
بيئة التطوير ستكون Microsoft Visual C++ 2008 Express Edtion و هي بيئة مجانية من ميكروسوفت
ملاحظة هذه الدورة لن تقوم باعطاءك معلومات عن ال OpenGL او GLUT سأفترض انك تعرف اساسيات هذه المكتبة كما ان المعلومات الواردة في الدورة صالحة للعمل مع اي مكتبة اخرى مثل DirectX
فهي معلومات اساسية ايضا سأفترض ان لديك معلومات ولو بسيطة عن لغة البرمجة C++ و معرفة بالبرمجة كائنية التوجه OOP
اخيرا الدروس فقط لمعرفة الفكرة العامة و ليس لتطوير محرك متكامل للالعاب
لنبدأ الدرس الأول : بناء محرك اللعبة
في هذا الدرس سوف نتعلم فصل كود اللعبة عن كود المكتبة او ما يسمى بمحرك اللعبة و مزايا الفصل كثيرة لعل من اهمها تجنب التكرار و التركيز على خوارزمية اللعبة و سهولة قراءة الكود و اخيرا
بعد تنقيح كود المحرك بامكانك اعادة استخدامه بامان في العاب اخرى و بسهولة مدهشة
لتجهيز مكتبة OpenGL للعمل في مشروع بسيط تحتاج لهذه الاسطر ( الاعدادت تختلف حسب المشروع في الكود التالي )
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(0,0);
glutInitWindowSize(640,480);
glutCreateWindow("BE Engine ....");
glutDisplayFunc(Render);
glutMainLoop();كما هو واضح يجب تجهيز بعض الدوال قبل انشاء النافذة بواسطة الدالة glutCreateWindow مثل اختيار نمط العرض DisplayMode و موقع و عرض النافذة وعنوانها
بعد انشاء النافذة نمرر الدالة التي نريدها ان تكون دالة رسم المشهد للدالة glutDisplayFunc ثم نقوم ببدء حلقة التكرار بواسطة الدالة glutMainLoop();
ستجد في المرفقات المثال الاول 1.1 يحتوي على هذا البرنامج البسيط الذي يقوم بانشاء نافذة و رسم مربع
بما ان كود انشاء النافذة لل OpenGL يتكرر تقريبا في كل الالعاب ( تجهيز DirectX يتكرر ايضا ) سنقوم بتغليفه في كائن Class بحيث عندما نقوم ببرمجة لعبة نقوم باضافة الكائن ثم استدعاءه في اللعبة
و هذا نطلق عليه مصطح محرك
اولا ننشيء كائن و ليكن اسمه BEngine ( اختصارا Borkan Engine ) محرك البركان و هذا الكائن هو كائن اللعبة الذي سيقوم بانشاء النافذة و ما يقوم به في الواقع هو تنفيذ الاسطر السابقة
سنضع تعريف الكائن و دواله في ملف واحد للتقليل من عدد الملفات
الملف BEngine.h
class BEngine
{
public:
BEngine(void)
{
}
~BEngine(void)
{
}
void CreateGame(int argc, char *argv[],void (*UserRender)(void));
void BeginRender();
void EndRender();
};طبعا سنقوم بتطوير الكائن اكثر فأكثر لاحقا و لكن حاليا ما يهمنا في كائن المحرك دالة انشاء اللعبة الدالة CreateGame و دالة BeginRender تقوم برسم المشهد
الدالة CreateGame
وظيفتها تجهيز glut للعمل و انشاء النافذة و هي تطلب المتغيرات التي تطلبها مكتبة glut ( تذكر كل ما نقوم به هو تغليف اي اعادة كتابة الكود في كائن )
المتغير الاول و الثاني بارمترات توفرها لنا الدالة الرئيسية للبرنامج اما المتغير الثالث فهي الدالة التي سيتم استدعائها لاعادة رسم المشهد
سوف نسلم المتغيرات التي استلمناها لدوال glut
هذه هي دالة انشاء اللعبة
void BEngine::CreateGame(int argc, char *argv[],void (*UserRender)(void))
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(0,0);
glutInitWindowSize(640,480);
glutCreateWindow("BE Engine 1.2 ....");
glutDisplayFunc(UserRender);
glutMainLoop();
}الان لدينا كائن يحتوي على الوظائف المكررة التي نستخدمها غالبا في انشاء اي لعبة و هذا الكائن يحتوي على وظيفة لانشاء اللعبة
بمان مكتبة glut تطلب تمرير دالة ليتم استدعائها ( callback ) لرسم المشهد فقد قمنا بطلب تلك دالة من المستخدم لكي نمررها بدورنا في وظيفة انشاء اللعبة و هي UserRender ثم مررناها كمتغير لمكتبة GLUT
glutDisplayFunc(UserRender);
اذا لم تفهم تمرير الدوال callbak فلا تقلق كل ما هناك اننا نخبر OpenGL انه خلال التكرار يجب عليه استدعاء الدالة UserRender التي سنرسم فيها
اخيرا الدالتين BeginRender و EndRender :
طبعا يمكن كتابة كود مسح الشاشة و اعادة الرسم في الدالة التي تمررها اللعبة للمحرك ( الكائن BEngine ) الا اننا ايضا نريد فصل هذه الاكواد و ضمها للكائن لجعل ملف اللعبة مستقلا لذا قمنا بانشاء دالتين لبدء و انهاء الرسم
الدالة BeginRender تحتوي على كود المسح
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
و الدالة EndRender تحتوي على كود انهاء عملية الرسم
glFlush (); glutSwapBuffers();
الان اصبح لدينا كائن محرك اللعبة
فقط نقوم بانشاء نسخة من هذا الكائن و انشاء دالة عرض
ثم داخل هذه الدالة نقوم باخبار المحرك ببدء الرسم ليتم مسح الرسم السابق ثم نقوم برسم الاشكال التي نريدها ثم اخباره بانهاء عملية الرسم
انظر لكود الملف main.cpp الجديد
المثال 1.2 في المرفقات يحتوي على كائن المحرك و ملف اللعبة بامكانك مقارنته بالمثال 1.1 السابق
#include "BEngine.h"
//انشاء نسخة من المحرك
BEngine mygame;
//الدالة المهتمة بالرسم
void PublicDisplay() {
// نخبر محرك اللعبة اننا نريد مسح المشهد السابق
mygame.BeginRender();
/*
عملية الرسم تتم هنا
*/
// نخبر المحرك اننا انهينا الرسم
mygame.EndRender();
}
int main (int argc, char *argv[])
{
// وظيفة انشاء اللعبة و نمرر لها اسم الدالة التي سيتم استدعائها لرسم مشهد اللعبة
mygame.CreateGame(argc ,argv,PublicDisplay);
return 0;
}كما ترى اصبح الملف الرئيسي سهل و بسيط و تم اخفاء التفاصيل الكثيرة داخل الكائن
بامكانك الان بدء اي لعبة بضم هذا الكائن و البدء مباشرة بالتطوير
هذا كل شيء في هذا الدرس
في الدرس القادم سنقوم ان شاء الله بتطوير كائن المحرك اكثر لنزيد من مرونته ثم ننتقل في الدروس التالية لكائنات اخرى
و آخر دعوانا ان الحمد لله رب العالمين
دعواتكم
