之前写了一片关于游戏引擎设计的文章,今天就用游戏引擎来实现一个小游戏(其实不算是严格意义上的游戏),主要就是为了感受游戏引擎给游戏设计带来的便利,而并不是游戏本身,使用游戏引擎之后你会发现,游戏设计会简便很多。它给你提供一个框架,而你所需要做的就是往里面填内容。
多得不说了,下面来看游戏引擎在游戏之中具体的使用。
先来想一想怎么在原来的游戏引擎上面填写内容,你需要在原来的基础上再新建一个游戏头文件以及游戏实现文件,关于游戏引擎上一篇内容已经讲过了,那么这一次只需要往里面填内容即可。
先来看看头文件Bizzard.h:
//Blizzard应用程序 //C++头文件-Blizzard.h #pragma once //-------------------------------------- //包含文件 //-------------------------------------- #include <Windows.h> #include <time.h> #include <tchar.h> #include "resource.h" #include "GameEngine.h" //-------------------------------------- //全局变量 //-------------------------------------- GameEngine * g_pGame = NULL; //每一个基于游戏引擎的游戏都需要一个全局游戏引擎指针
这个头文件中的指针为Blizzard对游戏引擎的访问,因此非常重要。
资源文件没什么可说的,它定义了在程序之中使用的所有的资源标识符,在这个例子之中比肩简单,只是定义了两个图标以及标题和名字,当然你还可以添加其他资源,这里就不再多说。
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 GameEngine.rc 使用 // #define IDS_APP_TITLE 101 #define IDC_BIZZARD 102 #define IDI_BLIZZARD 1000 #define IDI_BLIZZARD_SM 1001 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
最后来看一下重点的内容,就是游戏主体的实现:
//-------------------------------------- //Blizzard应用程序 //C++源程序 - - Blizzard.cpp //-------------------------------------- //-------------------------------------- //包含文件 //-------------------------------------- #include "Blizzard.h" //-------------------------------------- //游戏引擎函数 //-------------------------------------- BOOL GameInitialize(HINSTANCE hInstance) { //创建游戏引擎 g_pGame = new GameEngine(hInstance, TEXT("Blizzard"), TEXT("Blizzard"), IDI_BLIZZARD, IDI_BLIZZARD_SM); if (NULL == g_pGame) { return FALSE; } //设置帧频 g_pGame->SetFrameRate(10000); //15帧每秒,这里没必要使用默认的(20帧每秒) return TRUE; } void GameStart(HWND hWindow) { //生成随机生成器种子 srand((unsigned int)GetTickCount()); //如果游戏需要调用标准的rand()函数来生成随机数字,那么总是应该调用Srand()函数来指定随机数字生成器种子 } void GameEnd() { //清理游戏 delete g_pGame; } void GameActivate(HWND hWindow) { HDC hdc; RECT rect; //在游戏屏幕上绘制文本 GetClientRect(hWindow, &rect); hdc = GetDC(hWindow); DrawText(hdc, TEXT("Here comes the blizzard!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); ReleaseDC(hWindow, hdc); } void GameDeactivate(HWND hWindow) { HDC hdc; RECT rect; //在屏幕上绘制停用文本 GetClientRect(hWindow, &rect); hdc = GetDC(hWindow); DrawText(hdc, TEXT("The blizzard has passed."), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); ReleaseDC(hWindow, hdc); } void GamePaint(HDC hdc) { //在这个例子中没有必要调用这个重绘函数,因为所有的绘制工作都在GameCycle()函数之中就完成了,不过这种情况较为少见 } void GameCycle() { HDC hdc; HWND hWindow = g_pGame->GetWindow(); //在游戏屏幕上随机随机位置绘制雪花图标 hdc = GetDC(hWindow); DrawIcon(hdc, rand() % (g_pGame->GetWidth()), rand() % (g_pGame->GetHeight()), (HICON)(WORD)GetClassLong(hWindow, GCL_HICON)); ReleaseDC(hWindow, hdc); }
这里附上游戏引擎代码:
#pragma once //所要包含的文件 #include <windows.h> #define MAX_LOADSTRING 32 //windows函数声明 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); 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(); // //GameEngine // class GameEngine { protected: //成员变量 static GameEngine * m_pGameEngine; HINSTANCE m_hInstance; HWND m_hWindow; TCHAR m_szWindowClass[MAX_LOADSTRING]; TCHAR m_szTitle[MAX_LOADSTRING]; 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 = 640, int iHeight = 480); virtual ~GameEngine(); //常规方法 static GameEngine * GetEngine(){ return m_pGameEngine; }; BOOL Initialize(int nCmdShow); 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; }; };
游戏引擎源文件:
#include "GameEngine.h" GameEngine * GameEngine::m_pGameEngine = NULL; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; static int iTickTrigger = 0; int iTickCount; if (GameInitialize(hInstance)) { //初始化游戏引擎 if (!GameEngine::GetEngine()->Initialize(nCmdShow)) { return FALSE; } //进入主消息循环 while (TRUE) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { //处理消息 if (WM_QUIT == msg.message) { break; } TranslateMessage(&msg); DispatchMessage(&msg); } else { if (!GameEngine::GetEngine()->GetSleep()) { //检查滴答计数,看看是否过了一个周期 iTickCount = GetTickCount(); if (iTickCount - iTickTrigger) { iTickTrigger = iTickCount + GameEngine::GetEngine()->GetFrameDelay(); 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); } // //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_iHeight = iHeight; m_iWidth = iWidth; m_iFrameDelay = 20; //默认为20帧每秒 m_bSleep = TRUE; } //析构函数 GameEngine::~GameEngine() {} int GameEngine::Initialize(int nCmdShow) { //注册窗口类 WNDCLASSEX wndclass; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = (WNDPROC)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)GetStockObject(BLACK_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = m_szWindowClass; if (!RegisterClassEx(&wndclass)) { MessageBox(m_hWindow, L"注册窗口失败!", L"警告", MB_OK); 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 = CreateWindowEx(NULL, m_szWindowClass, m_szTitle, WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX, iXWindowPos, iYWindowPos, iWindowWidth, iWindowHeight, NULL, NULL, m_hInstance, NULL); if (!m_hWindow) { MessageBox(m_hWindow, L"创建窗口失败!", L"警告", MB_OK); return FALSE; } //更新和显示窗口 ShowWindow(m_hWindow,nCmdShow); 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); break; case WM_SETFOCUS: //激活游戏并更新休眠状态 GameActivate(hWindow); SetSleep(FALSE); break; case WM_KILLFOCUS: GameDeactivate(hWindow); SetSleep(TRUE); break; case WM_PAINT: PAINTSTRUCT ps; HDC hdc; hdc = BeginPaint(hWindow, &ps); //绘制游戏 GamePaint(hdc); EndPaint(hWindow, &ps); break; case WM_DESTROY: //结束游戏并退出应用程序 GameEnd(); PostQuitMessage(0); break; default: break; } return DefWindowProc(hWindow, msg, wParam, lParam); }
这样一个游戏就算制作完成了,此次博客主要倒不是游戏制作,而是游戏引擎带来的方便!
来看一下效果:
当然你可以换成更好看的图片,这样可以更好的看到雪花布满整个屏幕的感觉!
我试着换了一张图,效果如下:
如果想要将游戏做的更有乐趣,那么就可以不让它随机生成,而是有条件的生成,这样会更有乐趣!
时间: 2024-10-10 23:05:47