الدرس الثاني اضافة المزيد من المميزات للكائن الرئيسي للمحرك
في الدرس السابق قمنا بتصميم كائن Class و وضعنا داخله الوظائف الاساسية لانشاء نافذة glut و بذلك اصبح الكائن هو المسؤول عن انشاء النافذة
الا اننا نحتاج لكثير من الاشياء التي لا يلبيها الكائن بالشكل الحالي
مثلا :معلومات النافذة التي نريد انشاءها
انظر لهذا الكود
glutInitWindowPosition(0,0);
glutInitWindowSize(640,480);
glutCreateWindow("BE Engine 1.2 ....");في الكود السابق دوال glut المسؤولة عن النافذة .
الدالة الاولى تضع موقع النافذة اعتمادا على البارمترات المررة اليها و الدالة الثانية تحدد حجم النافذة ايضا تحتاج طول وعرض النافذة المطلوبة اخيرا الثالثة تحتاج عنوان للنافذة و تنشيء النافذة
اذا عدت لقراءة الكائن في الدرس السابق ستلاحظ اننا قمنا باعطاء قيم افتراضية .
في هذا الدرس سنقوم بجعل الكائن اكثر مرونة حيث يمكن اعطاء هذه القيم للكائن و هناك طريقتان لذلك الطريقة الاولى انشاء متغيرات للكائن و الطريقة الثانية انشاء Overload للدالة CreateGame و معنى Overload او ما يطلق عليها التحميل الزائد اننا ننشيء دالة بنفس الاسم مع زيادة البارمترات مثلا بارمتر عنوان النافذة
void CreateGame(int argc, char *argv[],void (*UserRender)(void),char *WindowText;);
و بالامكان الجمع بين الطريقتين كما في .NET FrameWork
بهدف تقليل عدد اعضاء الكائن BEngine لن نقوم باضافة المتغيرات كلها للكائن و عوضا عن ذلك سنقوم بانشاء تركيب و لنسميه مثلا Window و هذا التركيب يضم اهم خصائص النافذة ثم نمرره للكائن دفعة واحدة
هذا الاسلوب متبع في الدايركت اكس و لعل من قام بالعمل على DirectX يعرف ما اعنيه مثلا في DirectX
هذا التركيب الخاص بتجهيز البيانات الاساسية لل D3DDevice اسمه D3DPRESENT_PARAMETERS
typedef struct _D3DPRESENT_PARAMETERS
و نلاحظ انشاءه ثم تعبئته بالبيانات المطلوبة ثم انشاء جهاز العرض
D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof( d3dpp ) ); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // ثم انشاء جهاز العرض بتمرير التركيب السابق g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) )
حسنا لنعد ل OpenGL و للكائن BEngine تحديدا هذه بنية التركيب الذي سنقوم بجعله احد اعضاء كائن المحرك
struct BEWindow {
int Width;
int Height;
int X ,Y;
char *Text;
};اعضاء التركيب واضحة عرض و طول و موقع و عنوان النافذة
داخل الكائن BEngine سنضيف متغير من نوع التركيب Window
BEWindow Window ;
في دالة الانشاء للكائن سنقوم باعطاء التركيب قيم افتراضية يمكن للمبرمج تعديلها
BEngine(void)
{
// في دالة الانشاء نقوم بتجهيز التركيب
Window.X=0;
Window.Y=0;
Window.Width=640;
Window.Height=480;
Window.Text="BE Engine 1.2 ....";
}ايضا دالة انشاء النافذة هي الاخرى تغيرت لاننا سنقوم بانشاء النافذة بالقيم الموجودة في التركيب
void BEngine::CreateGame(int argc, char *argv[],void (*UserRender)(void))
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(Window.X,Window.Y);
glutInitWindowSize(Window.Width,Window.Height);
glutCreateWindow(Window.Text);
glutDisplayFunc(UserRender);
glutMainLoop();
}و سيصبح الكائن كالتالي
/*
كائن محرك اللعبة
برمجة حسين العصيمي
khwarzm@hotmail.com
*/
#pragma once
#include <GL/glut.h>
#ifndef BEngine_H
#define BEngine_H
struct BEWindow {
int Width;
int Height;
int X ,Y;
char *Text;
};
class BEngine
{
public:
BEngine(void)
{
// في دالة الانشاء نقوم بتجهيز التركيب
Window.X=0;
Window.Y=0;
Window.Width=640;
Window.Height=480;
Window.Text="BE Engine 1.3 ....";
}
~BEngine(void)
{
}
void CreateGame(int argc, char *argv[],void (*UserRender)(void));
void BeginRender();
void EndRender();
BEWindow Window ;
};
void BEngine::CreateGame(int argc, char *argv[],void (*UserRender)(void))
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(Window.X,Window.Y);
glutInitWindowSize(Window.Width,Window.Height);
glutCreateWindow(Window.Text);
glutDisplayFunc(UserRender);
glutMainLoop();
}
void BEngine::BeginRender(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void BEngine::EndRender(){
glFlush();
glutSwapBuffers();
}
#endifفي الملف الرئيسي main.cpp سنقوم بانشاء تركيب و نضع به الخصائص التي نريدها للنافذة ثم نمرر هذا التركيب للمحرك ثم ننشيء النافذة و نشاهد النتيجة
هذا هو الملف main.cpp
#include "BEngine.h"
//انشاء نسخة من المحرك
BEngine mygame;
//الدالة المهتمة بالرسم
void PublicDisplay() {
// نخبر محرك اللعبة اننا نريد مسح المشهد السابق
mygame.BeginRender();
/* عملية الرسم تتم هنا */
//====================================
//رسم مربع على الشاشة
glBegin(GL_QUADS);
glVertex3f(-0.5,-0.5,0.0);
glVertex3f(0.5,-0.5,0.0);
glVertex3f(0.5,0.5,0.0);
glVertex3f(-0.5,0.5,0.0);
glEnd();
//====================================
// نخبر المحرك اننا انهينا الرسم
mygame.EndRender();
}
int main (int argc, char *argv[])
{
//====================================
// انشاء تركيب نافذة
BEWindow wind;
wind.Width=320;
wind.Height=240;
wind.X=300;
wind.Y=200;
wind.Text="My Game ... ";
// تحديث معلومات النافذة في كائن المحرك
mygame.Window=wind;
//====================================
// وظيفة انشاء اللعبة و نمرر لها اسم الدالة التي سيتم استدعائها لرسم مشهد اللعبة
mygame.CreateGame(argc ,argv,PublicDisplay);
return 0;
}طبعا هدفنا هو المفهوم العام لذا لن نقوم بشرح خصائص اخرى غير هذا التركيب لان الفكرة واحدة
و اليك خصائص يمكنك اضافتها لون النافذة نمط الالوان دالة ايقاف اللعبة و الكثير الكثير
في المرفقات يمكنك الاطلاع على المثال 1.3 الذي قمنا بشرحه و مثال 1.4 و فيه اضفت خاصية لون الخلفية
الى اللقاء في الدرس القادم
لا تنسونا من دعواتكم
