一个简单的2d游戏引擎
2014-01-13 11:27
543 查看
头文件 GameEngine.h
#pragma once #include<windows.h> #include<list> #include"Sprite.h" using namespace std; 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(); void HandleKeys(); void MouseButtonDown(int x,int y,BOOL bLeft); void MouseButtonUp(int x,int y,BOOL bLeft); void MouseMove(int x,int y); BOOL SpriteCollision(Sprite* pSpriteHitter, Sprite* pSpriteHittee); void SpriteDying(Sprite* pSpriteDying);//游戏知道何时破坏子画面非常有用的。例如,在破坏一个流星子面面时,可以创建一个爆炸子画面。 /* GameEngine类 */ 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; list<Sprite*> m_vSprites; UINT m_uiMIDIPlayerID; // Helper Methods BOOL CheckSpriteCollision(Sprite* pTestSprite); public: //构造函数、析构函数 GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass, LPTSTR szTitle, WORD wIcon, WORD wSmallIcon, int iWidth = 640, int iHeight = 480); virtual ~GameEngine(); //常规方法 static GameEngine* GetEngine(){return m_pGameEngine;} BOOL Initialize(int iCmdShow); LRESULT HandleEvent(HWND hWindow,UINT msg, WPARAM wParam, LPARAM lParam); void AddSprite(Sprite* pSprite); void DrawSprites(HDC hDC); void UpdateSprites(); void CleanupSprites(); Sprite* IsPointInSprite(int x, int y); void PlayMIDISong(LPTSTR szMIDIFileName = TEXT(""),BOOL bRestart = TRUE); void PauseMIDISong(); void CloseMIDIPlayer(); //访问方法 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; //windows函数 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()){ //检查滴答计数,查看是否过了一个游戏周期 /* note:这里看不太懂,为什么iTickTrigger在iTickCount上不断加一个FrameDelay。 iTickCount和iTickTrigger为什么不用模运算呢? */ iTickCount = GetTickCount(); if(iTickCount > iTickTrigger){ iTickTrigger = iTickCount + GameEngine::GetEngine()->GetFrameDelay(); HandleKeys(); GameCycle(); } } } } return (int)msg.wParam; } GameEnd(); return TRUE; } LRESULT CALLBACK WndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam){ //将所有windows消息都传递给游戏引擎 return GameEngine::GetEngine()->HandleEvent(hWindow,msg,wParam,lParam); } //----------------------------------------------------------------- // Game Engine Helper Methods //----------------------------------------------------------------- BOOL GameEngine::CheckSpriteCollision(Sprite* pTestSprite) { // See if the sprite has collided with any other sprites list<Sprite*>::iterator siSprite; for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++) { // Make sure not to check for collision with itself if (pTestSprite == (*siSprite)) continue; // Test the collision if (pTestSprite->TestCollision(*siSprite)) // Collision detected return SpriteCollision((*siSprite), pTestSprite); } // No collision return FALSE; } /* GameEngine的构造函数、析构函数 */ GameEngine::GameEngine(HINSTANCE hInstance,LPTSTR szWindowClass,LPTSTR szTitle, WORD wIcon,WORD wSmallIcon, int iWidth, int iHeight){ //设置游戏引擎的成员变量 m_pGameEngine = this; m_hInstance = hInstance; /* note: why m_hWindow = NULL? */ 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; //默认为20帧/秒 m_bSleep = TRUE; m_uiMIDIPlayerID = 0; } 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 + 1); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = m_szWindowClass; //注册窗口类 if(!RegisterClassEx(&wndclass)) return FALSE; //根据游戏大小计算窗口大小和位置 int iWindowWidth = m_iWidth + GetSystemMetrics(SM_CXFIXEDFRAME) * 2; int 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; int iYWindowPos = (GetSystemMetrics(SM_CYSCREEN)-iWindowHeight)/2; //创建窗口 m_hWindow = CreateWindow(m_szWindowClass,m_szTitle,WS_POPUPWINDOW| WS_CAPTION|WS_MINIMIZEBOX, iXWindowPos,iYWindowPos, 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){ //将Windows消息传递给游戏引擎成员函数 switch(msg){ case WM_CREATE: //设置游戏窗口并开始游戏 SetWindow(hWindow); GameStart(hWindow); return 0; case WM_SETFOCUS: //激活游戏并更新休眠状态 GameActivate(hWindow); SetSleep(FALSE); return 0; case WM_KILLFOCUS: //停用游戏并更新休眠状态 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_LBUTTONDOWN: MouseButtonDown(LOWORD(lParam),HIWORD(lParam),TRUE); return 0; case WM_LBUTTONUP: MouseButtonUp(LOWORD(lParam),HIWORD(lParam),TRUE); case WM_RBUTTONDOWN: MouseButtonDown(LOWORD(lParam),HIWORD(lParam),FALSE); return 0; case WM_RBUTTONUP: MouseButtonUp(LOWORD(lParam),HIWORD(lParam),FALSE); return 0; case WM_MOUSEMOVE: MouseMove(LOWORD(lParam),HIWORD(lParam)); return 0; case WM_DESTROY: //结束游戏并退出应用程序 GameEnd(); PostQuitMessage(0); return 0; } return DefWindowProc(hWindow,msg,wParam,lParam); } void GameEngine::AddSprite(Sprite* pSprite){ // Add a sprite to the sprite list if (pSprite != NULL){ // See if there are sprites already in the sprite list if (m_vSprites.size() > 0){ // Find a spot in the sprite list to insert the sprite by its z-order list<Sprite*>::iterator siSprite; for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++){ if (pSprite->GetZOrder() < (*siSprite)->GetZOrder()){ // Insert the sprite into the sprite vector m_vSprites.insert(siSprite, pSprite); return; } } } // The sprite's z-order is highest, so add it to the end of the list m_vSprites.push_back(pSprite); } } void GameEngine::DrawSprites(HDC hDC) { // Draw the sprites in the sprite list list<Sprite*>::iterator siSprite; for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++) (*siSprite)->Draw(hDC); } void GameEngine::UpdateSprites() { // Update the sprites in the sprite list RECT rcOldSpritePos; SPRITEACTION saSpriteAction; list<Sprite*>::iterator siSprite; for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end();) { // Save the old sprite position in case we need to restore it rcOldSpritePos = (*siSprite)->GetPosition(); // Update the sprite saSpriteAction = (*siSprite)->Update(); // Handle the SA_ADDSPRITE sprite action if (saSpriteAction & SA_ADDSPRITE) // Allow the sprite to add its sprite AddSprite((*siSprite)->AddSprite()); // Handle the SA_KILL sprite action if (saSpriteAction & SA_KILL) { //Notify the game that the sprite is dying SpriteDying(*siSprite); //Kill the sprite delete (*siSprite); siSprite = m_vSprites.erase(siSprite); continue; } // See if the sprite collided with any others if (CheckSpriteCollision(*siSprite)){ // Restore the old sprite position (*siSprite)->SetPosition(rcOldSpritePos); } ++siSprite; } } void GameEngine::CleanupSprites(){ // Delete and remove the sprites in the sprite list while(!m_vSprites.empty()){ delete(m_vSprites.back()); m_vSprites.pop_back(); } } Sprite* GameEngine::IsPointInSprite(int x, int y){ // See if the point is in a sprite in the sprite list list<Sprite*>::reverse_iterator siSprite; for (siSprite = m_vSprites.rbegin(); siSprite != m_vSprites.rend(); siSprite++) if (!(*siSprite)->IsHidden() && (*siSprite)->IsPointInside(x, y)) return (*siSprite); // The point is not in a sprite return NULL; } void GameEngine::PlayMIDISong(LPTSTR szMIDIFileName, BOOL bRestart) { // See if the MIDI player needs to be opened if (m_uiMIDIPlayerID == 0){ // Open the MIDI player by specifying the device and filename MCI_OPEN_PARMS mciOpenParms; mciOpenParms.lpstrDeviceType = TEXT("sequencer"); mciOpenParms.lpstrElementName = szMIDIFileName; if (mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD_PTR)&mciOpenParms) == 0){ // Get the ID for the MIDI player m_uiMIDIPlayerID = mciOpenParms.wDeviceID; }else{ // There was a problem, so just return return; } } // Restart the MIDI song, if necessary if (bRestart) { MCI_SEEK_PARMS mciSeekParms; if (mciSendCommand(m_uiMIDIPlayerID, MCI_SEEK, MCI_SEEK_TO_START, (DWORD_PTR)&mciSeekParms) != 0) // There was a problem, so close the MIDI player CloseMIDIPlayer(); } // Play the MIDI song MCI_PLAY_PARMS mciPlayParms; if (mciSendCommand(m_uiMIDIPlayerID, MCI_PLAY, 0, (DWORD_PTR)&mciPlayParms) != 0) // There was a problem, so close the MIDI player CloseMIDIPlayer(); } void GameEngine::PauseMIDISong() { // Pause the currently playing song, if possible if (m_uiMIDIPlayerID != 0) mciSendCommand(m_uiMIDIPlayerID, MCI_PAUSE, 0, NULL); } void GameEngine::CloseMIDIPlayer() { // Close the MIDI player, if possible if (m_uiMIDIPlayerID != 0) { mciSendCommand(m_uiMIDIPlayerID, MCI_CLOSE, 0, NULL); m_uiMIDIPlayerID = 0; } }
相关文章推荐
- python hard way中的一个小例子,简单的游戏引擎
- 【技术讨论】从弹弹堂说起,如何用2D物理引擎编写一个游戏<一>2011-11-05 10:36
- 【技术讨论】从弹弹堂说起,如何用2D物理引擎编写一个游戏<一>
- 开源3D&2D游戏开发引擎之GoDot简单介绍(一)
- 暂时保留一个2d的游戏引擎
- 比较简单的2D游戏引擎C++类
- Cocos2d-HTML5游戏引擎,编写一个简单的打飞机游戏
- 一个简单的基于OpenGL的Lua的游戏引擎的实例
- UWP简单示例(三):快速开发2D游戏引擎
- Cocos2d-x 是一个支持多平台的 2D 手机游戏引擎
- Unity 2D游戏开发快速入门第1章创建一个简单的2D游戏
- [入门教程]使用Cocos2d-html5游戏引擎编写一个简单的游戏 第一回合: 搭建开发环境
- Unity3D 创建一个简单的2D游戏
- android 2D游戏开发,引擎设计(四) 造型类Model的设计。简单进度条
- 一个容易上手的2D游戏引擎love2d (lua)
- 【Android2D游戏开发十六】(上文之触摸屏手势)详解Android Gesture 手势操作!利用手势实现一个简单切换图片的功能!
- Unity3D 创建一个简单的2D游戏
- 【技术讨论】从弹弹堂说起,如何用2D物理引擎编写一个游戏&lt;一&gt;2011-11-05 10:36
- Godot教程中文版-一个简单的2D游戏(Simple 2D Game,Pong!)
- 一个简单的游戏引擎核心状态机的C++实现