当前位置:   article > 正文

一个简单的2d游戏引擎_pmdsplayer game engine 2d 2014

pmdsplayer game engine 2d 2014
头文件 GameEngine.h
  1. #pragma once
  2. #include<windows.h>
  3. #include<list>
  4. #include"Sprite.h"
  5. using namespace std;
  6. int WINAPI WINMAIN(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow);
  7. LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
  8. /*
  9. 以下函数的特定实现是游戏特有的,必须由使用该游戏引擎的各个游戏提供
  10. */
  11. BOOL GameInitialize(HINSTANCE hInstance);
  12. void GameStart(HWND hWindow);
  13. void GameEnd();
  14. void GameActivate(HWND hWindow);
  15. void GameDeactivate(HWND hWindow);
  16. void GamePaint(HDC hDC);
  17. void GameCycle();
  18. void HandleKeys();
  19. void MouseButtonDown(int x,int y,BOOL bLeft);
  20. void MouseButtonUp(int x,int y,BOOL bLeft);
  21. void MouseMove(int x,int y);
  22. BOOL SpriteCollision(Sprite* pSpriteHitter, Sprite* pSpriteHittee);
  23. void SpriteDying(Sprite* pSpriteDying);//游戏知道何时破坏子画面非常有用的。例如,在破坏一个流星子面面时,可以创建一个爆炸子画面。
  24. /*
  25. GameEngine类
  26. */
  27. class GameEngine{
  28. protected:
  29. static GameEngine *m_pGameEngine;
  30. HINSTANCE m_hInstance;
  31. HWND m_hWindow;
  32. TCHAR m_szWindowClass[32];
  33. TCHAR m_szTitle[32];
  34. WORD m_wIcon,m_wSmallIcon;
  35. int m_iWidth,m_iHeight;
  36. int m_iFrameDelay;
  37. BOOL m_bSleep;
  38. list<Sprite*> m_vSprites;
  39. UINT m_uiMIDIPlayerID;
  40. // Helper Methods
  41. BOOL CheckSpriteCollision(Sprite* pTestSprite);
  42. public:
  43. //构造函数、析构函数
  44. GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass, LPTSTR szTitle,
  45. WORD wIcon, WORD wSmallIcon, int iWidth = 640, int iHeight = 480);
  46. virtual ~GameEngine();
  47. //常规方法
  48. static GameEngine* GetEngine(){return m_pGameEngine;}
  49. BOOL Initialize(int iCmdShow);
  50. LRESULT HandleEvent(HWND hWindow,UINT msg, WPARAM wParam, LPARAM lParam);
  51. void AddSprite(Sprite* pSprite);
  52. void DrawSprites(HDC hDC);
  53. void UpdateSprites();
  54. void CleanupSprites();
  55. Sprite* IsPointInSprite(int x, int y);
  56. void PlayMIDISong(LPTSTR szMIDIFileName = TEXT(""),BOOL bRestart = TRUE);
  57. void PauseMIDISong();
  58. void CloseMIDIPlayer();
  59. //访问方法
  60. HINSTANCE GetInstance(){return m_hInstance;}
  61. HWND GetWindow(){return m_hWindow;}
  62. void SetWindow(HWND hWindow){m_hWindow = hWindow;}
  63. LPTSTR GetTitle(){return m_szTitle;}
  64. WORD GetIcon(){return m_wIcon;}
  65. WORD GetSmallIcon(){return m_wSmallIcon;}
  66. int GetWidth(){return m_iWidth;}
  67. int GetHeight(){return m_iHeight;}
  68. int GetFrameDelay(){return m_iFrameDelay;}
  69. void SetFrameRate(int iFrameRate){m_iFrameDelay = 1000/iFrameRate;}
  70. BOOL GetSleep(){return m_bSleep;}
  71. void SetSleep(BOOL bSleep){m_bSleep = bSleep;}
  72. };

GameEngine.cpp

 

  1. #include "GameEngine.h"
  2. //静态变量初始
  3. GameEngine *GameEngine::m_pGameEngine = NULL;
  4. //windows函数
  5. int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow){
  6. MSG msg;
  7. static int iTickTrigger = 0;
  8. int iTickCount;
  9. if(GameInitialize(hInstance)){
  10. //初始化游戏引擎
  11. if(!GameEngine::GetEngine()->Initialize(iCmdShow)){
  12. return false;
  13. }
  14. //进入主消息循环
  15. while(TRUE){
  16. if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
  17. //处理消息
  18. if(msg.message == WM_QUIT){
  19. break;
  20. }
  21. TranslateMessage(&msg);
  22. DispatchMessage(&msg);
  23. }else{
  24. //确保游戏引擎没有休眠
  25. if(!GameEngine::GetEngine()->GetSleep()){
  26. //检查滴答计数,查看是否过了一个游戏周期
  27. /*
  28. note:这里看不太懂,为什么iTickTrigger在iTickCount上不断加一个FrameDelay。
  29. iTickCount和iTickTrigger为什么不用模运算呢?
  30. */
  31. iTickCount = GetTickCount();
  32. if(iTickCount > iTickTrigger){
  33. iTickTrigger = iTickCount + GameEngine::GetEngine()->GetFrameDelay();
  34. HandleKeys();
  35. GameCycle();
  36. }
  37. }
  38. }
  39. }
  40. return (int)msg.wParam;
  41. }
  42. GameEnd();
  43. return TRUE;
  44. }
  45. LRESULT CALLBACK WndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam){
  46. //将所有windows消息都传递给游戏引擎
  47. return GameEngine::GetEngine()->HandleEvent(hWindow,msg,wParam,lParam);
  48. }
  49. //-----------------------------------------------------------------
  50. // Game Engine Helper Methods
  51. //-----------------------------------------------------------------
  52. BOOL GameEngine::CheckSpriteCollision(Sprite* pTestSprite)
  53. {
  54. // See if the sprite has collided with any other sprites
  55. list<Sprite*>::iterator siSprite;
  56. for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
  57. {
  58. // Make sure not to check for collision with itself
  59. if (pTestSprite == (*siSprite))
  60. continue;
  61. // Test the collision
  62. if (pTestSprite->TestCollision(*siSprite))
  63. // Collision detected
  64. return SpriteCollision((*siSprite), pTestSprite);
  65. }
  66. // No collision
  67. return FALSE;
  68. }
  69. /*
  70. GameEngine的构造函数、析构函数
  71. */
  72. GameEngine::GameEngine(HINSTANCE hInstance,LPTSTR szWindowClass,LPTSTR szTitle, WORD wIcon,WORD wSmallIcon, int iWidth, int iHeight){
  73. //设置游戏引擎的成员变量
  74. m_pGameEngine = this;
  75. m_hInstance = hInstance;
  76. /*
  77. note: why m_hWindow = NULL?
  78. */
  79. m_hWindow = NULL;
  80. if(lstrlen(szWindowClass)>0){
  81. lstrcpy(m_szWindowClass, szWindowClass);
  82. }
  83. if(lstrlen(szTitle)>0){
  84. lstrcpy(m_szTitle,szTitle);
  85. }
  86. m_wIcon = wIcon;
  87. m_wSmallIcon = wSmallIcon;
  88. m_iWidth = iWidth;
  89. m_iHeight = iHeight;
  90. m_iFrameDelay = 50; //默认为20帧/秒
  91. m_bSleep = TRUE;
  92. m_uiMIDIPlayerID = 0;
  93. }
  94. GameEngine::~GameEngine(){
  95. }
  96. /*
  97. 游戏引擎常规方法
  98. */
  99. BOOL GameEngine::Initialize(int iCmdShow){
  100. WNDCLASSEX wndclass;
  101. //创建主窗口的窗口类
  102. wndclass.cbSize = sizeof(wndclass);
  103. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  104. wndclass.lpfnWndProc = WndProc;
  105. wndclass.cbClsExtra = 0;
  106. wndclass.cbWndExtra = 0;
  107. wndclass.hInstance = m_hInstance;
  108. wndclass.hIcon = LoadIcon(m_hInstance,MAKEINTRESOURCE(GetIcon()));
  109. wndclass.hIconSm = LoadIcon(m_hInstance,MAKEINTRESOURCE(GetSmallIcon()));
  110. wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
  111. wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  112. wndclass.lpszMenuName = NULL;
  113. wndclass.lpszClassName = m_szWindowClass;
  114. //注册窗口类
  115. if(!RegisterClassEx(&wndclass))
  116. return FALSE;
  117. //根据游戏大小计算窗口大小和位置
  118. int iWindowWidth = m_iWidth + GetSystemMetrics(SM_CXFIXEDFRAME) * 2;
  119. int iWindowHeight = m_iHeight + GetSystemMetrics(SM_CYFIXEDFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION);;
  120. if(wndclass.lpszMenuName != NULL) iWindowHeight += GetSystemMetrics(SM_CYMENU);
  121. int iXWindowPos = (GetSystemMetrics(SM_CXSCREEN)-iWindowWidth)/2;
  122. int iYWindowPos = (GetSystemMetrics(SM_CYSCREEN)-iWindowHeight)/2;
  123. //创建窗口
  124. m_hWindow = CreateWindow(m_szWindowClass,m_szTitle,WS_POPUPWINDOW|
  125. WS_CAPTION|WS_MINIMIZEBOX, iXWindowPos,iYWindowPos, iWindowWidth,iWindowHeight, NULL,NULL, m_hInstance, NULL);
  126. if(!m_hWindow) return FALSE;
  127. ShowWindow(m_hWindow,iCmdShow);
  128. UpdateWindow(m_hWindow);
  129. return TRUE;
  130. }
  131. LRESULT GameEngine::HandleEvent(HWND hWindow, UINT msg, WPARAM wParam,LPARAM lParam){
  132. //将Windows消息传递给游戏引擎成员函数
  133. switch(msg){
  134. case WM_CREATE:
  135. //设置游戏窗口并开始游戏
  136. SetWindow(hWindow);
  137. GameStart(hWindow);
  138. return 0;
  139. case WM_SETFOCUS:
  140. //激活游戏并更新休眠状态
  141. GameActivate(hWindow);
  142. SetSleep(FALSE);
  143. return 0;
  144. case WM_KILLFOCUS:
  145. //停用游戏并更新休眠状态
  146. GameDeactivate(hWindow);
  147. SetSleep(TRUE);
  148. return 0;
  149. case WM_PAINT:
  150. HDC hDC;
  151. PAINTSTRUCT ps;
  152. hDC = BeginPaint(hWindow,&ps);
  153. //绘制游戏
  154. GamePaint(hDC);
  155. EndPaint(hWindow,&ps);
  156. return 0;
  157. //鼠标事件
  158. case WM_LBUTTONDOWN:
  159. MouseButtonDown(LOWORD(lParam),HIWORD(lParam),TRUE);
  160. return 0;
  161. case WM_LBUTTONUP:
  162. MouseButtonUp(LOWORD(lParam),HIWORD(lParam),TRUE);
  163. case WM_RBUTTONDOWN:
  164. MouseButtonDown(LOWORD(lParam),HIWORD(lParam),FALSE);
  165. return 0;
  166. case WM_RBUTTONUP:
  167. MouseButtonUp(LOWORD(lParam),HIWORD(lParam),FALSE);
  168. return 0;
  169. case WM_MOUSEMOVE:
  170. MouseMove(LOWORD(lParam),HIWORD(lParam));
  171. return 0;
  172. case WM_DESTROY:
  173. //结束游戏并退出应用程序
  174. GameEnd();
  175. PostQuitMessage(0);
  176. return 0;
  177. }
  178. return DefWindowProc(hWindow,msg,wParam,lParam);
  179. }
  180. void GameEngine::AddSprite(Sprite* pSprite){
  181. // Add a sprite to the sprite list
  182. if (pSprite != NULL){
  183. // See if there are sprites already in the sprite list
  184. if (m_vSprites.size() > 0){
  185. // Find a spot in the sprite list to insert the sprite by its z-order
  186. list<Sprite*>::iterator siSprite;
  187. for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++){
  188. if (pSprite->GetZOrder() < (*siSprite)->GetZOrder()){
  189. // Insert the sprite into the sprite vector
  190. m_vSprites.insert(siSprite, pSprite);
  191. return;
  192. }
  193. }
  194. }
  195. // The sprite's z-order is highest, so add it to the end of the list
  196. m_vSprites.push_back(pSprite);
  197. }
  198. }
  199. void GameEngine::DrawSprites(HDC hDC)
  200. {
  201. // Draw the sprites in the sprite list
  202. list<Sprite*>::iterator siSprite;
  203. for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
  204. (*siSprite)->Draw(hDC);
  205. }
  206. void GameEngine::UpdateSprites()
  207. {
  208. // Update the sprites in the sprite list
  209. RECT rcOldSpritePos;
  210. SPRITEACTION saSpriteAction;
  211. list<Sprite*>::iterator siSprite;
  212. for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end();)
  213. {
  214. // Save the old sprite position in case we need to restore it
  215. rcOldSpritePos = (*siSprite)->GetPosition();
  216. // Update the sprite
  217. saSpriteAction = (*siSprite)->Update();
  218. // Handle the SA_ADDSPRITE sprite action
  219. if (saSpriteAction & SA_ADDSPRITE)
  220. // Allow the sprite to add its sprite
  221. AddSprite((*siSprite)->AddSprite());
  222. // Handle the SA_KILL sprite action
  223. if (saSpriteAction & SA_KILL)
  224. {
  225. //Notify the game that the sprite is dying
  226. SpriteDying(*siSprite);
  227. //Kill the sprite
  228. delete (*siSprite);
  229. siSprite = m_vSprites.erase(siSprite);
  230. continue;
  231. }
  232. // See if the sprite collided with any others
  233. if (CheckSpriteCollision(*siSprite)){
  234. // Restore the old sprite position
  235. (*siSprite)->SetPosition(rcOldSpritePos);
  236. }
  237. ++siSprite;
  238. }
  239. }
  240. void GameEngine::CleanupSprites(){
  241. // Delete and remove the sprites in the sprite list
  242. while(!m_vSprites.empty()){
  243. delete(m_vSprites.back());
  244. m_vSprites.pop_back();
  245. }
  246. }
  247. Sprite* GameEngine::IsPointInSprite(int x, int y){
  248. // See if the point is in a sprite in the sprite list
  249. list<Sprite*>::reverse_iterator siSprite;
  250. for (siSprite = m_vSprites.rbegin(); siSprite != m_vSprites.rend(); siSprite++)
  251. if (!(*siSprite)->IsHidden() && (*siSprite)->IsPointInside(x, y))
  252. return (*siSprite);
  253. // The point is not in a sprite
  254. return NULL;
  255. }
  256. void GameEngine::PlayMIDISong(LPTSTR szMIDIFileName, BOOL bRestart)
  257. {
  258. // See if the MIDI player needs to be opened
  259. if (m_uiMIDIPlayerID == 0){
  260. // Open the MIDI player by specifying the device and filename
  261. MCI_OPEN_PARMS mciOpenParms;
  262. mciOpenParms.lpstrDeviceType = TEXT("sequencer");
  263. mciOpenParms.lpstrElementName = szMIDIFileName;
  264. if (mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
  265. (DWORD_PTR)&mciOpenParms) == 0){
  266. // Get the ID for the MIDI player
  267. m_uiMIDIPlayerID = mciOpenParms.wDeviceID;
  268. }else{
  269. // There was a problem, so just return
  270. return;
  271. }
  272. }
  273. // Restart the MIDI song, if necessary
  274. if (bRestart)
  275. {
  276. MCI_SEEK_PARMS mciSeekParms;
  277. if (mciSendCommand(m_uiMIDIPlayerID, MCI_SEEK, MCI_SEEK_TO_START,
  278. (DWORD_PTR)&mciSeekParms) != 0)
  279. // There was a problem, so close the MIDI player
  280. CloseMIDIPlayer();
  281. }
  282. // Play the MIDI song
  283. MCI_PLAY_PARMS mciPlayParms;
  284. if (mciSendCommand(m_uiMIDIPlayerID, MCI_PLAY, 0,
  285. (DWORD_PTR)&mciPlayParms) != 0)
  286. // There was a problem, so close the MIDI player
  287. CloseMIDIPlayer();
  288. }
  289. void GameEngine::PauseMIDISong()
  290. {
  291. // Pause the currently playing song, if possible
  292. if (m_uiMIDIPlayerID != 0)
  293. mciSendCommand(m_uiMIDIPlayerID, MCI_PAUSE, 0, NULL);
  294. }
  295. void GameEngine::CloseMIDIPlayer()
  296. {
  297. // Close the MIDI player, if possible
  298. if (m_uiMIDIPlayerID != 0)
  299. {
  300. mciSendCommand(m_uiMIDIPlayerID, MCI_CLOSE, 0, NULL);
  301. m_uiMIDIPlayerID = 0;
  302. }
  303. }

 

 

编码请看:http://www.maidoupig.cn

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/87521
推荐阅读
相关标签
  

闽ICP备14008679号