الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

2D Game Engine

مغلق
بدأه خليل أونيس في 21 أبريل 2005 · 13 رد · 1,849 مشاهدة · في قسم برمجة الألعاب و الرسوميات العام
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم

سأضع اليوم المحرك و غدا إن شاء الله نبدأ في الشرح و المناقشات

سنبدأ بمحرك بسيط جدا و هو ::

// GameEngine.h //

#include <windows.h>

int WINAPI WinMain(HINSTANCE  hInstance,
       HINSTANCE  hPrevInstance,
                   PSTR    szCmdLine,
       int    iCmdShow);

LRESULT CALLBACK  WndProc(HWND  	hWnd, 
        UINT  	msg,
        WPARAM  wParam, 
        LPARAM  lParam);

//-----------------------------------------------------------------
// إعلان عن دوال المحرك
//-----------------------------------------------------------------
BOOL	GameInitialize(HINSTANCE hInstance);
void	GameStart(HWND hWindow);
void	GameEnd();
void	GameActivate(HWND hWindow);
void	GameDeactivate(HWND hWindow);
void	GamePaint(HDC hDC);
void	GameCycle();
int  GameEFullScreen();

//-----------------------------------------------------------------
// طبقة المحرك
//-----------------------------------------------------------------
class GameEngine
{
protected:
	// مجموعة متغيرات
	static GameEngine*  m_pGameEngine;
	HINSTANCE           m_hInstance;
	HWND                m_hWindow;
	TCHAR               m_szWindowClass[32];
	TCHAR               m_szTitle[32];
	WORD                m_wIcon, m_wSmallIcon;
	int                 m_iWidth, m_iHeight;
	int                 m_iFrameDelay;
	BOOL                m_bSleep;

public:
	// البناء و التدمير
	GameEngine(HINSTANCE  hInstance, 
      LPTSTR  	szWindowClass, 
      LPTSTR  	szTitle,
      WORD  	wIcon, 
      WORD  	wSmallIcon, 
      int  	iWidth = 800, 
      int  	iHeight = 600);

	virtual ~GameEngine();

	static GameEngine*  GetEngine() 
	{ 
  return m_pGameEngine; 
	};

	BOOL                Initialize(int iCmdShow);
	LRESULT             HandleEvent(HWND  hWindow, 
            UINT  msg, 
            WPARAM  wParam,
            LPARAM  lParam);

	HINSTANCE GetInstance() 
	{ 
  return m_hInstance; 
	};

	HWND      GetWindow() 
	{ 
  return m_hWindow; 
	};

	void      SetWindow(HWND hWindow) 
	{ 
  m_hWindow = hWindow; 
	};

	LPTSTR    GetTitle() 
	{
  return m_szTitle; 
	};

	WORD      GetIcon() 
	{ 
  return m_wIcon; 
	};

	WORD      GetSmallIcon() 
	{ 
  return m_wSmallIcon;
	};

	int       GetWidth() 
	{ 
  return m_iWidth;
	};

	int       GetHeight() 
	{ 
  return m_iHeight; 
	};

	int       GetFrameDelay() 
	{ 
  return m_iFrameDelay; 
	};

	void      SetFrameRate(int iFrameRate) 
	{ 
  m_iFrameDelay = 1000 /iFrameRate; 
	};

	BOOL      GetSleep() 
	{ 
  return m_bSleep; 
	};

	void      SetSleep(BOOL bSleep) 
	{ 
  m_bSleep = bSleep; 
	};
};

// GameEngine.cpp //

#include "GameEngine.h"

//-----------------------------------------------------------------
// تهيئة متغيرات الساكنة
//-----------------------------------------------------------------
GameEngine *GameEngine::m_pGameEngine = NULL;


GameEFullScreen()
{
	DEVMODE GameEScreenSettings;
	memset(&GameEScreenSettings,0,sizeof(GameEScreenSettings));
	GameEScreenSettings.dmSize=sizeof(GameEScreenSettings);
	GameEScreenSettings.dmPelsWidth  = 800;
	GameEScreenSettings.dmPelsHeight	= 600;
	GameEScreenSettings.dmBitsPerPel	= 32;
	GameEScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

	if (ChangeDisplaySettings(&GameEScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
	{
  return 0;
	}

	return 1;
}

//-----------------------------------------------------------------
// دوال النافذة
//-----------------------------------------------------------------

int WINAPI WinMain(HINSTANCE  hInstance, 
       HINSTANCE  hPrevInstance,
       PSTR    szCmdLine, 
       int    iCmdShow)
{
	MSG         msg;
	static int  iTickTrigger = 0;
	int         iTickCount;

	if (GameInitialize(hInstance))
	{
  // تشغيل محرك اللعبة
  if (!GameEngine::GetEngine()->Initialize(iCmdShow))
  {
  	return FALSE;
  }
  
  // إدخل حلقة الرسالة الرئيسية
  
  while (TRUE)
  {
  	if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  	{
    // معالجة الرسائل
    if (msg.message == WM_QUIT)
    {
    	break;
    }
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  	}
  	else
  	{
    // التأكد من عدم توقف المحرك
    if (!GameEngine::GetEngine()->GetSleep())
    {
    	// الفحص في دورات اللعبة
    	iTickCount = GetTickCount();
    	if (iTickCount > iTickTrigger)
    	{
      iTickTrigger = iTickCount + GameEngine::GetEngine()->GetFrameDelay();
      GameCycle();
      GameEFullScreen();
    	}
    }
  	}
  }
  return (int)msg.wParam;
	}
	// نهاية اللعبة
	GameEnd();
	return TRUE;
}

LRESULT CALLBACK WndProc(HWND  hWindow, 
       UINT  msg, 
       WPARAM  wParam, 
       LPARAM  lParam)
{
	// توجيه جميع رسائل إلى محرك اللعبة
	return GameEngine::GetEngine()->HandleEvent(hWindow, msg, wParam, lParam);
}

//-----------------------------------------------------------------
// مبني و مهدم المحرك
//-----------------------------------------------------------------
GameEngine::GameEngine(HINSTANCE  hInstance,
        LPTSTR   szWindowClass,
        LPTSTR   szTitle, 
        WORD    wIcon,
        WORD    wSmallIcon, 
        int    iWidth,
        int    iHeight)
{
	// وضع متغيرات في محرك اللعبة
	m_pGameEngine  = this;
	m_hInstance  = hInstance;
	m_hWindow  	= NULL;

	if (lstrlen(szWindowClass) > 0)
	{
  lstrcpy(m_szWindowClass, szWindowClass);
	}

	if (lstrlen(szTitle) > 0)
	{
  lstrcpy(m_szTitle, szTitle);
	}

	m_wIcon    = wIcon;
	m_wSmallIcon  = wSmallIcon;
	m_iWidth  	= iWidth;
	m_iHeight  	= iHeight;
	m_iFrameDelay  = 50;
	m_bSleep  	= TRUE;
}

GameEngine::~GameEngine()
{

}

//-----------------------------------------------------------------
// إستعمال المحرك
//-----------------------------------------------------------------
BOOL GameEngine::Initialize(int iCmdShow)
{
	WNDCLASSEX    wndclass;

	// إنشاء فيئة نافذة للنافذة الرئيسية
	wndclass.cbSize         = sizeof(wndclass);
	wndclass.style          = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc    = WndProc;
	wndclass.cbClsExtra     = 0;
	wndclass.cbWndExtra     = 0;
	wndclass.hInstance      = m_hInstance;
	wndclass.hIcon          = LoadIcon(m_hInstance,MAKEINTRESOURCE(GetIcon()));
	wndclass.hIconSm        = LoadIcon(m_hInstance,MAKEINTRESOURCE(GetSmallIcon()));
	wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 12);
	wndclass.lpszMenuName   = NULL;
	wndclass.lpszClassName  = m_szWindowClass;

	// تسجيل فئة النافذة
	if (!RegisterClassEx(&wndclass))
	{
  return FALSE;
	}

	// حسابة موقع و حجم النافذة ...
	int iWindowWidth = m_iWidth + GetSystemMetrics(SM_CXFIXEDFRAME) * 2,iWindowHeight = m_iHeight + GetSystemMetrics(SM_CYFIXEDFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION);

	if (wndclass.lpszMenuName != NULL)
	{
  iWindowHeight += GetSystemMetrics(SM_CYMENU);
	}

	int iXWindowPos = (GetSystemMetrics(SM_CXSCREEN) - iWindowWidth) / 2,iYWindowPos = (GetSystemMetrics(SM_CYSCREEN) - iWindowHeight) / 2;

	// إنشاء النافذة
	m_hWindow = CreateWindow(m_szWindowClass, m_szTitle, WS_EX_TOPMOST | WS_POPUP | WS_VISIBLE, 0, 0, iWindowWidth,iWindowHeight, NULL, NULL, m_hInstance, NULL);

	if (!m_hWindow)
	{
  return FALSE;
	}

	// إظهار و تحديث النافذة
	ShowWindow(m_hWindow, iCmdShow);
	UpdateWindow(m_hWindow);

	return TRUE;
}

LRESULT GameEngine::HandleEvent(HWND  hWindow, 
        UINT  msg,
        WPARAM  wParam, 
        LPARAM  lParam)
{
	switch (msg)
	{
	case WM_CREATE:
  // وضع نافذة اللعبة وإبدأ اللعبة
  SetWindow(hWindow);
  GameStart(hWindow);

  return 0;
	case WM_ACTIVATE:
  // تنشيط و إيقاف التنشيط للعبة
  if (wParam != WA_INACTIVE)
  {
  	GameActivate(hWindow);
  	SetSleep(FALSE);
  }
  else
  {
  	GameDeactivate(hWindow);
  	SetSleep(TRUE);
  }

  return 0;

	case WM_PAINT:
  HDC         hDC;
  PAINTSTRUCT ps;
  hDC = BeginPaint(hWindow, &ps);
  
  // رسم اللعبة
  GamePaint(hDC);
  EndPaint(hWindow, &ps);
  
  return 0;

	case WM_DESTROY:
  // نهاية العبة و الخروج منها
  GameEnd();
  PostQuitMessage(0);
  return 0;
	}
	return DefWindowProc(hWindow, msg, wParam, lParam);
}

// GameE.cpp //

#include <windows.h>
#include "GameEngine.h"

//-----------------------------------------------------------------
// متغيرات
//-----------------------------------------------------------------
GameEngine* GameE;
//-----------------------------------------------------------------
// دوال المحرك
//-----------------------------------------------------------------
BOOL GameInitialize(HINSTANCE hInstance)
{
	// إنشاء المحرك
	GameE = new GameEngine(hInstance, "GameE","GameE", 0, 0);
	if (GameE == NULL)
	{
  return FALSE;
	}

	// وضع نسبة الإيطار
	GameE->SetFrameRate(15);

  return TRUE;
}

void GameStart(HWND hWindow)
{
	// إستعمال المولد العشوائي
	srand(GetTickCount());
}

void GameEnd()
{
	// مسح محرك اللعبة
	ChangeDisplaySettings(NULL,0);
	delete GameE;
}

void GameActivate(HWND hWindow)
{
	/*في حالة التنشيط*/
}

void GameDeactivate(HWND hWindow)
{
	/* في حالة إيقاف تنشيط المحرك*/
}

void GamePaint(HDC hDC)
{
	// لرسم
}

void GameCycle()
{
	// ما سيحدث
}

سنتحدث غدا في ::

* ماهي المحركات

* لماذا تصنع المحركات و مافئدتها

* و شرح للشفرات

أتمنى أن يكون هناك من يساعدنا و يشاركنا الموضوع

و السلام

GameE.rar

تم تعديل هذه المشاركة بواسطة GameDev4Arab في 21 أبريل 2005 في 19:17

#2

فكرة جميلة, انا عندي محرك ascii graphics ربما احاول وضعه و شرحه ايضا ان شاء الله,

واصل و الله يوفقك

#3

:s شكرا أخي حسان على التشجيع و لكن للأسف لا يوجد أي تفاعل و إن لم يكن التفاعل لن يكون الشرح و أنا آسف

اقتباس
انا عندي محرك ascii graphics ربما احاول وضعه و شرحه ايضا ان شاء الله

إذا ضعه لكي نناقشه

#4

عندما كتبته اعتبرته تحفة! لكن الآن اعتبره دون المطلوب. و احاول الان اعادة كتابته.

هذا القديم:

الكود

اللعبة

تم تعديل هذه المشاركة بواسطة hasan_aljudy في 23 أبريل 2005 في 00:56

#5
اقتباس
شكرا أخي حسان على التشجيع و لكن للأسف لا يوجد أي تفاعل و إن لم يكن التفاعل لن يكون الشرح و أنا آسف

اسف اخوي...لكن انشغلت كثيرا...

والمشكلة اني لا افهم كثيرا بالبرمجة الكائنية..وبالتالي اخشى من وضع معلومة خاطئة ...

اتمنى ان تبادروا(والطلب الى جميع الاعضاء) في شرح كيفية تغليف الدوال وبعض لامور الاخرى التي تخص الكائنات..نريد البداية منكم... وان شاء الله نفيد ونستفيد...

ولاتنسى انه يوجد الكثير من الاعضاء .... الفاهمين .. ننتظرهم.

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#6

أخي حسان محركك رائعة و إن شاء الله سأضن أنا محرك مشابه له و لكنه سيكون أفضل منه بكثير :)

و تشكر أخي

لا مشكلة أخي الشمري ربما أكون قد أخطأت أي تسرعت كثيرا في وضعه

أخي كريم إن شاء الله غدا أفسر ذلك

و شكرا

#7

قمت بتجربة محركك. يا حسن . فعلا رائع ..

اتمنى لو اصل لمستواك

لكن مشكلتي تكمن في عدم اتقاني للكائنات الى الان..لاني لم اعود نفسي على استخدامها

كنت افكر بعمل محرك خلال العطلة القادمة بحول الله.. مستخدم opengl ...

اتمنى يا حسن لو تبذل جهد مضاعف وتبدأ بالتعمق في opengl لانك مهيء تماما لتعلمها..

اتمنى لك التوفيق...

--------------

يبدو الموضوع توقف!!!

اتمنى ان يتم شرح ولو جزئيا بعض ماكتبه gamedev كل يضيف مالديه...

سأبدا بتعليق بسيط..

عندما تريد ترتيب الكود الذي تكتبه تقسمه لدوال..مثلا دالة للرسم دالة لبداية تنفيذ

الشاشة(اعدادت) دالة لمسح وتنظيف الذاكرة من مخلفات لعبتنا..وهكذا..

لكن عندما يكبر الكود سنضيع بين عشرات الدوال... لذا يقوم المبرمجون بتغليفها.. مامعنى ذلك

؟

يعني يضعون كائنات كل كائن يضم عدد من الدوال والمتغيرات التي تقوم بعمل ما..

مثلا كائن الرسم.. ويضم

دالة(او كائن) يقوم برسم مثلث

دالة(او كائن) يقوم برسم مربع

دالة(او كائن) يقوم برسم مكعب

وهكذا

دالة للاكساء

وتضم عدة فلاتر خاصة بالاكساء..وعدة خصائص..

وهكذا..

مثال

ساضع مثال تقريبي حتى يبين المقصود من المحرك..

بدل من كتابة عشرات الاسطر حتى نرسم مثلث ونقوم باكسائه..نكتفي بتغليفه(وضع المتغيرات

والدوال في كائن) فيصبح كائن ونسميه مثلا CSHAPE ويحوي على عدة دوال منها دالة لرسم

مكعب...

CSHAPE shape1

shape1.cube(x=1,y=2,z=-3,size=5);

الان وبكل سهولة نقوم برسمه من خلال سطر واحد..

هذا هو المحرك...يعني كيف نستطيع عمل كود معين باقصر وافضل طرق....

طبعا احيانا نحتاج للوراثة وتعدد الواجهات..وغيرها من مكونات الفئات....

هذا مالدي الان اتمنى من كل واحد اضافة تعليقات بسيطة وبالتالي تتضح معالم المحرك الذي

طرحه اخونا gamedev4arab>>وان لا نكون(عديمين الاحساس ... فقط نريد منه الدروس

ونحن نتفرج)

----

شاركوا...:)

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#8

مشكور جدا أخي الشمري

اقتباس
يبدو الموضوع توقف!!!

مأقتا :)

لأني أولا :: لم أجد التفاعل الذي كنت أريده

ثانيا :: هو الوقت

و لكن عندما أجد الوقت سأقوم بتوضيح بعض الأشياء إن شاء الله

و شكرا أخي

#9

انا عندي امتحانات هذه الأيام, فاصبروا قليلا ان شاء الله. و ادعولي.

#10

بالنسبة لمحركي (التعبان) فهو كان في الأصل مصمم لاستخدام function يوفره visual c++ على ما أظن, اسمه WriteConsoleOutput ياخذ buffer او بالأحرى array من نوع خاص اسمه CHAR_INFO و هو struct بسيط يحتوي على حرف و "لون" ..

فهذا الفنكشن ياخذ هذا البفر, و لازم تعطيه الأبعاد طبعا, و هو يتولى رسمه على الشاشة في أي مكان ترغب فيه.

المهم فيما بعد قمت بكتابة فنكشن آخر يحاول القيام بنفس العملية (رغم انه بطييييئ جدا بالمقارنة .. لكنه يفي بالغرض), و بدأت استخدم الفنكشن الآخر بدل ذلك.

المهم الفكرة هو رسم الكائنات على ذلك البفر و تفريغ البفر على الشاشة في كل فريم.

و الكانئات هي عبارة عن sprites كل واحد منها له موقع و يستطيع ان يتحرك. و طبعا المحرك هو اللذي يتولي متابعة كل الكائنات و متابعة مواقعها, و في كل فريم يمر على لستة الكائنات و يحدثها و يرسمها. و هذاكله في لووب تستمر الى نهاية اللعبة

و بس ..

اما بالنسبة للكتابة اللتي تظهر عند نهاية اللعبة, فقد استخدمت كودا كتبه شخص آخر في احد المنتديات و استأذنته ان استخدم الكود و وافق هو على ذلك (بل فرح بذلك)

هذا باختصار, اما التفاصيل فلاحقا إن شاء الله

تم تعديل هذه المشاركة بواسطة hasan_aljudy في 26 أبريل 2005 في 00:26

#11
اقتباس
بالنسبة لمحركي (التعبان)

حلو التواضع B)

بالعكس بالمقارنة مع مستوياتنا يعتبر محرك رائع + منظم

اول مرة افهم شي من المحركات.. :blink:

مشكلتي اني لا اعرف اجعل برنامجي كائن المنحنى .... فلا اعرف كيف اسخّر ميزات OOP لصالح محركي..

اتمنى ان تتكلم عن محركك.. من ناحية الكائنات والتغليف فهذا ما يهمنا في هذا الموضوع...

اذا كان عندك وقت ..

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#12
اقتباس
بالنسبة لمحركي (التعبان)

المحرك رائع أخي و خاصة طريقتك في إستعماله

اقتباس
هذا باختصار, اما التفاصيل فلاحقا إن شاء الله

بإنتظارك :)

#13

هو تعبان من جهتين: أولا انه ascii يعني مستوى الجرافكس على قد الحال :D

لكن هذا ليس بمشكلة ..

المشكلة في الحقيقة هي انني كتبته قبل ان اخذس كورس في الكلية حول الـobject oriented programming أما الآن, و قد انهيت هذا الكورس (الامتحان النهائي كان اليوم) .. فقد اكتشفت الكثير من العيوب في تصميم المحرك ..

تم تعديل هذه المشاركة بواسطة hasan_aljudy في 26 أبريل 2005 في 20:48

#14

هذا الموضوع مميز ... لكن .. كاتبه .. غائب من فترة .. الله يوفقه .

من يريد الاضافة :) ،،،

مشغول حاليا لكن اتمنى لو ارجع بعد كم اسبوع واجده 17 صفحة ...

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

هذا الموضوع مغلق.

مواضيع مشابهة