[置頂] Win32游戲制作之---Bizzard
來源:程序員人生 發布時間:2016-06-12 15:49:07 閱讀次數:2524次
之前寫了1片關于游戲引擎設計的文章,今天就用游戲引擎來實現1個小游戲(其實不算是嚴格意義上的游戲),主要就是為了感受游戲引擎給游戲設計帶來的便利,而其實不是游戲本身,使用游戲引擎以后你會發現,游戲設計會簡便很多。它給你提供1個框架,而你所需要做的就是往里面填內容。
多得不說了,下面來看游戲引擎在游戲當中具體的使用。
先來想想怎樣在原來的游戲引擎上面填寫內容,你需要在原來的基礎上再新建1個游戲頭文件和游戲實現文件,關于游戲引擎上1篇內容已講過了,那末這1次只需要往里面填內容便可。
先來看看頭文件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; //每個基于游戲引擎的游戲都需要1個全局游戲引擎指針
這個頭文件中的指針為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
最后來看1下重點的內容,就是游戲主體的實現:
//--------------------------------------
//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!"), ⑴, &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."), ⑴, &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())
{
//檢查滴答計數,看看是不是過了1個周期
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);
}
這樣1個游戲就算制作完成了,此次博客主要倒不是游戲制作,而是游戲引擎帶來的方便!
來看1下效果:

固然你可以換成更好看的圖片,這樣可以更好的看到雪花布滿全部屏幕的感覺!
我試著換了1張圖,效果以下:

如果想要將游戲做的更有樂趣,那末就能夠不讓它隨機生成,而是有條件的生成,這樣會更有樂趣!
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈