📄 gameengine.cpp
字号:
//-----------------------------------------------------------------
// Game Engine Object
// C++ Source - 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())
{
//------检查滴答计数--------
iTickCount = GetTickCount();
if (iTickCount > iTickTrigger)
{
iTickTrigger = iTickCount +
GameEngine::GetEngine()->GetFrameDelay();
HandleKeys();
GameEngine::GetEngine()->CheckJoystick();
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);
}
//-----------------------------------------------------------------
// 游戏引擎帮助器方法
//-----------------------------------------------------------------
BOOL GameEngine::CheckSpriteCollision(Sprite* pTestSprite)
{
// See if the sprite has collided with any other sprites
vector<Sprite*>::iterator siSprite;
for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
{
//确保没有将子画面与它自身相比较
if (pTestSprite == (*siSprite))
continue;
// 在两个子画面之间执行碰撞测试
if (pTestSprite->TestCollision(*siSprite))
// 检测到碰撞则响应碰撞
return SpriteCollision((*siSprite), pTestSprite);
}
// 没有碰撞
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;
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_uiJoystickID = 0;
m_vSprites.reserve(100);
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,
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_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);
return 0;
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::ErrorQuit(LPTSTR szErrorMsg)
{
MessageBox(GetWindow(), szErrorMsg, TEXT("Critical Error"), MB_OK | MB_ICONERROR);
PostQuitMessage(0);
}
BOOL GameEngine::InitJoystick()
{
//确保存在游戏杆驱动程序
UINT uiNumJoysticks;
if ((uiNumJoysticks = joyGetNumDevs()) == 0)
return FALSE;
//确保连接了游戏杆
JOYINFO jiInfo;
if (joyGetPos(JOYSTICKID1, &jiInfo) != JOYERR_UNPLUGGED)
m_uiJoystickID = JOYSTICKID1;
else
return FALSE;
//计算移动值
JOYCAPS jcCaps;
joyGetDevCaps(m_uiJoystickID, &jcCaps, sizeof(JOYCAPS));
DWORD dwXCenter = ((DWORD)jcCaps.wXmin + jcCaps.wXmax) / 2;
DWORD dwYCenter = ((DWORD)jcCaps.wYmin + jcCaps.wYmax) / 2;
m_rcJoystickTrip.left = (jcCaps.wXmin + (WORD)dwXCenter) / 2;
m_rcJoystickTrip.right = (jcCaps.wXmax + (WORD)dwXCenter) / 2;
m_rcJoystickTrip.top = (jcCaps.wYmin + (WORD)dwYCenter) / 2;
m_rcJoystickTrip.bottom = (jcCaps.wYmax + (WORD)dwYCenter) / 2;
return TRUE;
}
void GameEngine::CaptureJoystick()
{
//捕获游戏杆
if (m_uiJoystickID == JOYSTICKID1)
joySetCapture(m_hWindow, m_uiJoystickID, NULL, TRUE);
}
void GameEngine::ReleaseJoystick()
{
//释放游戏杆
if (m_uiJoystickID == JOYSTICKID1)
joyReleaseCapture(m_uiJoystickID);
}
void GameEngine::CheckJoystick()
{
if (m_uiJoystickID == JOYSTICKID1)
{
JOYINFO jiInfo;
JOYSTATE jsJoystickState = 0;
if (joyGetPos(m_uiJoystickID, &jiInfo) == JOYERR_NOERROR)
{
//检查水平移动
if (jiInfo.wXpos < (WORD)m_rcJoystickTrip.left)
jsJoystickState |= JOY_LEFT;
else if (jiInfo.wXpos > (WORD)m_rcJoystickTrip.right)
jsJoystickState |= JOY_RIGHT;
//检查垂直移动
if (jiInfo.wYpos < (WORD)m_rcJoystickTrip.top)
jsJoystickState |= JOY_UP;
else if (jiInfo.wYpos > (WORD)m_rcJoystickTrip.bottom)
jsJoystickState |= JOY_DOWN;
//检查按钮
if(jiInfo.wButtons & JOY_BUTTON1)
jsJoystickState |= JOY_FIRE1;
if(jiInfo.wButtons & JOY_BUTTON2)
jsJoystickState |= JOY_FIRE2;
}
//允许游戏处理游戏杆
HandleJoystick(jsJoystickState);
}
}
void GameEngine::AddSprite(Sprite* pSprite) //向子画面列表添加子画面
{
// Add a sprite to the sprite vector
if (pSprite != NULL)
{
// See if there are sprites already in the sprite vector
if (m_vSprites.size() > 0)
{
// Find a spot in the sprite vector to insert the sprite by its z-order
vector<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 vector
m_vSprites.push_back(pSprite);
}
}
void GameEngine::DrawSprites(HDC hDC) //绘制子画面列表中的所有子画面
{
// Draw the sprites in the sprite vector
vector<Sprite*>::iterator siSprite;
for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
(*siSprite)->Draw(hDC);
}
void GameEngine::UpdateSprites() //更新各个子画面的位置
{
// Expand the capacity of the sprite vector, if necessary
if (m_vSprites.size() >= (m_vSprites.capacity() / 2))
m_vSprites.reserve(m_vSprites.capacity() * 2);
// Update the sprites in the sprite vector
RECT rcOldSpritePos;
SPRITEACTION saSpriteAction;
vector<Sprite*>::iterator siSprite;
for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
{
// 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);
m_vSprites.erase(siSprite);
siSprite--;
continue;
}
// See if the sprite collided with any others
if (CheckSpriteCollision(*siSprite))
// Restore the old sprite position
(*siSprite)->SetPosition(rcOldSpritePos);
}
}
void GameEngine::CleanupSprites() //从内存中释放子画面并清空子画面矢量
{
// Delete and remove the sprites in the sprite vector
vector<Sprite*>::iterator siSprite;
for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
{
delete (*siSprite);
m_vSprites.erase(siSprite);
siSprite--;
}
}
Sprite* GameEngine::IsPointInSprite(int x, int y) //查看一个点是否位于子画面列表的某个子画面内部
{
// See if the point is in a sprite in the sprite vector
vector<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) //打开MIDI播放器
{
// 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 = "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() //关闭MIDI设备并清空设备ID
{
// Close the MIDI player, if possible
if (m_uiMIDIPlayerID != 0)
{
mciSendCommand(m_uiMIDIPlayerID, MCI_CLOSE, 0, NULL);
m_uiMIDIPlayerID = 0;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -