收藏 分销(赏)

Windows游戏编程快速入门方法.doc

上传人:xrp****65 文档编号:7666648 上传时间:2025-01-11 格式:DOC 页数:96 大小:1.42MB
下载 相关 举报
Windows游戏编程快速入门方法.doc_第1页
第1页 / 共96页
Windows游戏编程快速入门方法.doc_第2页
第2页 / 共96页
点击查看更多>>
资源描述
Windows游戏编程快速入门方法 Easideao(简单思路) 序言: 从2001年到2005年,在不知不觉中我已经渡过了4年的职业游戏开发生涯。在这4年里经常会有些网友向我询问编程的入门有没有捷径。每一次我都不知怎么回答才算合适,我也一直想表达一下我的思路和想法,但一直都没有能力把自己的见解在书面上表达出来,其实我认为编写程序并不是很难的事情。最关键的是你对他是否有兴趣,最难的是坚持学习。如果没有兴趣,即使你刚刚入了一点们如果不坚持下去,也是一事无成。 虽然毅力在学习的过程中有着不可置疑的位置,但是有个合适的方法和适合自己的方法还是很重要的。假如你的兴趣和毅力都过了关,我接下来将以一个游戏的代码编写过程写下来,我坚持写下来,你坚持读完,按照我讲述的步骤去做。我这里不会把所有细节都讲述出来,因为那是太庞大的任务,我的力量无法实现,我们下面的方法就是:我说怎么做,你就怎么做,先知道怎样做一些事情,当你能够按照我说的做出正确的结果说明你已经会了,如果有不懂得再去查看相关资料。 上面说的有些繁琐,我自己也不太愿意写下去了,我的文笔水平有限,请大家谅解。接下来最重要的就是跟着我做。如果你有什么意见或问题可以给我发E-mail : chinagdh@。 第一章 Windows程序 1. 打开Visual Studio ,选择File -> Blank Solution。 2. 在Name栏里输入 BattleCity 并按 ok 按钮, 按browse选择解决方案存放位置 3.在Solution Explorer 里在 Solution ‘BattleCity’上按右键。在下拉菜单中选择 Add -> New Project。 4.在Add New Project 对话框里选择 Visual C++ Projects -> Win32 -> Win32 Project,在Name栏里打入 Tank 并按回车 5.选择Application Settings 并在 Empty project 前面打钩,创建一个空的Win32 项目。 6.在Tank项目上按右键 选择Add -> New Folder 增加文件夹,并命名WinApp 7.在WinApp文件夹上按右键 选择Add -> Add New Item 8.选择Visual C++ -> C++ File(.cpp) 在Name栏里输入 WinApp.cpp。 9.反复7.8步 增加 WinApp.h AppEntry.cpp AppEntry.h 10.双击 WinApp.h 打开文件 我们在WinApp.h头文件中加入以下代码 11.以同样的方法处理AppEntry.h , 这种方法保证头文件只被include一次,这是我喜欢用的一种方法也可以在第一行写#pragma once 12.打开AppEntry.h 加入代码 #include <windows.h> 13.打开WinApp.h 加入代码 #include "AppEntry.h" 14.打开WinApp.cpp 加入代码 #include "WinApp.h" 15.定义主程序句柄和主窗口句柄 16.增加获得主程序句柄和主窗口句柄的全局函数 17. 为方便以后获得主程序句柄和主窗口句柄 在 WinApp.h 中声明 HINSTANCE GetAppHandle(); HWND GetMainWnd(); 18.定义Windows程序主函数,这是一个Windows程序的入口函数,我们认为程序从此函数开始执行。 19.在Solution Explorer 中选择Tank项目,按右键选择Build 编译一下,看程序是否可以编译。 编译成功会在Output窗口中出现提示信息 Build:1 succeeded, 0 failed, 0 skipped 表示 成功一个 0 失败 0 跳过 20.设置Tank生成的路径,在项目Tank上按右键选择Properties 21.选择程序生成路径(Output File)为 ../RunTime/Tank.exe 22.选择运行路径(Working Directory) 为 ../RunTime 在编译一下 23.增加必要的几个函数 程序的初始化 结束 主循环 消息处理函数,代码如下 #include "WinApp.h" // 定义主程序句柄 HINSTANCE g_hTheApp = NULL; // 定义主窗口句柄 HWND g_hMainWnd = NULL; ////////////////////////////////////////////////////////////////////////// // 获得主程序句柄 HINSTANCE GetAppHandle() { return g_hTheApp; } // 获得主窗口句柄 HWND GetMainWnd() { return g_hMainWnd; } ////////////////////////////////////////////////////////////////////////// // Windows程序初始化 HWND AppInit( HINSTANCE hInstance, int nShowCmd ); // Windows程序结束 void AppTerm(); // Windows消息循环和主循环 int AppMsgLoop(); // Windows消息处理函数 LRESULT CALLBACK AppWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); ////////////////////////////////////////////////////////////////////////// // Windows程序主函数 int WINAPI WinMain( IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd ) { // 保存主程序句柄 g_hTheApp = hInstance; // 初始化Window窗口和程序 g_hMainWnd = AppInit( g_hTheApp, nShowCmd ); if( g_hMainWnd == NULL ) { MessageBox( NULL, "Can't Create Main Window", "Error", MB_OK ); return 0; } // 进入主消息循环 return AppMsgLoop(); } // Windows程序初始化 HWND AppInit( HINSTANCE hInstance, int nShowCmd ) { return NULL; } // Windows程序结束 void AppTerm() { } // Windows消息循环和主循环 int AppMsgLoop() { return 0; } // Windows消息处理函数 LRESULT CALLBACK AppWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { return DefWindowProc( hWnd, msg, wParam, lParam ); } 24.在AppInit()函数里注册程序和创建主窗口 // Windows程序初始化 HWND AppInit( HINSTANCE hInstance, int nShowCmd ) { // 程序实例类名 static char szWindowsClassName[] = "TankBattleCity"; static int iWindowWidth = 800; // 窗口宽度 static int iWindowHeight = 600; // 窗口高度 // 注册窗口类 WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; // 设置主窗口消息处理函数 wc.lpfnWndProc = AppWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon( 0, IDI_APPLICATION ); wc.hCursor = LoadCursor( 0, IDC_ARROW ); wc.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); wc.lpszMenuName = 0; wc.lpszClassName = szWindowsClassName; if( !RegisterClass( &wc ) ) { MessageBox( NULL, "RegisterClass - Failed", "Error", MB_OK ); return false; } // 创建主窗口 HWND hWnd = CreateWindow( szWindowsClassName , szWindowsClassName , WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX , CW_USEDEFAULT , CW_USEDEFAULT , iWindowWidth , iWindowHeight , 0 , 0 , hInstance , 0 ); if( NULL == hWnd ) { MessageBox( NULL, "Create Main Window - Failed", "Error", MB_OK ); return NULL; } // 显示主窗口 ShowWindow( hWnd, SW_SHOW ); // 更新主窗口显示内容 UpdateWindow( hWnd ); return hWnd; } 25.编写AppMsgLoop() 的程序主循环 // Windows消息循环和主循环 int AppMsgLoop() { MSG msg; ZeroMemory( &msg, sizeof(MSG) ); _AppLoop: // 检测是否有消息要处理 if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) { // 如果接收不到消息表示要退出程序 if( !GetMessage( &msg, NULL, 0, 0 ) ) { // 转向结束程序 goto _ExitApp; } // 执行消息处理 TranslateMessage( &msg ); DispatchMessage( &msg ); } else { // 如果没有任何消息要处理就调用主循环 Sleep(1); } goto _AppLoop; _ExitApp: AppTerm(); return (int)msg.wParam; } 26.在AppWndProc()函数里加入推出程序消息处理 // Windows消息处理函数 LRESULT CALLBACK AppWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_DESTROY: PostQuitMessage( 0 ); break; } return DefWindowProc( hWnd, msg, wParam, lParam ); } 到现在我们已经可以编译并执行一个没有做任何事情的Windows程序,这里我不想和任何人讨论关于编码好坏的问题,例如在AppMsgLoop()函数中用了goto和标号。我个人觉得在这里不适宜讨论这个问题。我们重要的是知道如何让程序工作,有关于Windows编程的细节你可以查阅《Windows程序设计》一书。 第二章 简化的程序接口 前一章中我们介绍了如何编写Windows程序,已经完成了一个简单的有一个主窗口的Windows程序,接下来我们钻心写我们的游戏程序了。为了以后的编写方便使各部分程序内容彼此独立,我们现在开始定义一个程序简单的程序接口,我们以后就不需要再顾虑太多的Windows程序相关的内容。 程序接口的实现我们用到了C++中最常用的一种功能 虚拟函数(virtual function) 来实现接口功能。在这里你只需要知道在基类中定义的函数前面加了一个virtual关键字,以后派生类中都可以重写该函数内容。 1. 打开AppEntry.h 输入下面程序 #ifndef __AppEntry_H__ #define __AppEntry_H__ #include <windows.h> class IAppEntry { public: // 初始化程序 virtual bool Initialize( HINSTANCE hInstance, HWND hWnd ) = 0; // 结束程序 virtual void Terminal() = 0; // 主处理函数 virtual void Process() = 0; // 主渲染函数 virtual void Render() = 0; // 主窗口消息处理函数 virtual LRESULT WndProc( UINT message, WPARAM wParam, LPARAM lParam ) = 0; // 定义Window程序类名函数 virtual const char *WindowClassName() = 0; // 定义Window窗口宽度 virtual const int WindowWidth() = 0; // 定义Window窗口高度 virtual const int WindowHeight() = 0; // 获得 主程序句柄 virtual HINSTANCE GetInstance() = 0; // 获得 主窗口句柄 virtual HWND GetWnd() = 0; }; #endif // __AppEntry_H__ 这里每一个函数 后面都写了一个 = 0 表示该函数是纯虚函数, 再派生类中必须重写。这种方法是定义接口的常用方法。 2. 打开WinApp.cpp 加入下面代码 // Windows消息循环和主循环 int AppMsgLoop(); // Windows消息处理函数 LRESULT CALLBACK AppWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); // 获得简单程序接口实例,我们将在GameApp.cpp中定义 IAppEntry *AppEntryClass(); ////////////////////////////////////////////////////////////////////////// // Windows程序主函数 int WINAPI WinMain( IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd ) 3. 在WinMain函数中加入下面代码 // Windows程序主函数 int WINAPI WinMain( IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd ) { // 保存主程序句柄 g_hTheApp = hInstance; // 初始化Window窗口和程序 g_hMainWnd = AppInit( g_hTheApp, nShowCmd ); if( g_hMainWnd == NULL ) { MessageBox( NULL, "Can't Create Main Window", "Error", MB_OK ); return 0; } // 初始化主程序 if( !AppEntryClass()->Initialize( g_hTheApp, g_hMainWnd ) ) { MessageBox( NULL, "Initialize AppEntry Failed", "Error", MB_OK ); return 0; } // 进入主消息循环 return AppMsgLoop(); } 4. 在AppTerm() 函数里加入下面代码 // Windows程序结束 void AppTerm() { // 结束程序 AppEntryClass()->Terminal(); } 5. 在AppMsgLoop()函数里加入下面代码 // Windows消息循环和主循环 int AppMsgLoop() { MSG msg; ZeroMemory( &msg, sizeof(MSG) ); _AppLoop: // 检测是否有消息要处理 if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) { // 如果接收不到消息表示要退出程序 if( !GetMessage( &msg, NULL, 0, 0 ) ) { // 转向结束程序 goto _ExitApp; } // 执行消息处理 TranslateMessage( &msg ); DispatchMessage( &msg ); } else { // 如果没有任何消息要处理就调用主循环 AppEntryClass()->Process(); Sleep(1); } goto _AppLoop; _ExitApp: AppTerm(); return (int)msg.wParam; } 6. 在AppWndProc()函数里加入下面代码 // Windows消息处理函数 LRESULT CALLBACK AppWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_DESTROY: PostQuitMessage( 0 ); break; } // 调用简单程序接口的消息处理函数,如果返回不是FALSE 就直接完成消息处理 // 否则 继续调用Windows程序默认消息处理函数. LRESULT lr = AppEntryClass()->WndProc( msg, wParam, lParam ); if( lr != FALSE ) return lr; return DefWindowProc( hWnd, msg, wParam, lParam ); } 7. 在Tank项目上建一个新目录GameApp并创建两个文件 AppGame.cpp AppGame.h 8. 在AppGame.h里 加入下面代码 #ifndef __AppGame_H__ #define __AppGame_H__ #include "WinApp.h" class CAppGame : public IAppEntry { public: CAppGame(); virtual ~CAppGame(); // 初始化程序 virtual bool Initialize( HINSTANCE hInstance, HWND hWnd ); // 结束程序 virtual void Terminal(); // 主处理函数 virtual void Process(); // 主渲染函数 virtual void Render(); // 主窗口消息处理函数 virtual LRESULT WndProc( UINT message, WPARAM wParam, LPARAM lParam ); // 定义Window程序类名函数 virtual const char *WindowClassName(); // 定义Window窗口宽度 virtual const int WindowWidth(); // 定义Window窗口高度 virtual const int WindowHeight(); // 获得 主程序句柄 virtual HINSTANCE GetInstance(); // 获得 主窗口句柄 virtual HWND GetWnd(); protected: // 保存主程序句柄 HINSTANCE m_hInstance; // 保存主窗口句柄 HWND m_hWnd; }; #endif // __AppGame_H__ 9. 打开AppGame.cpp 加入简单接口程序实例,和获得程序实例的函数 #include "AppGame.h" // 定义主游戏程序实例 CAppGame theAppGame; // 定义获得简单程序接口实例函数,这个在WinApp.cpp中用到,而且必须定义 // 这是Windows程序调用游戏程序的接口 IAppEntry *AppEntryClass() { return &theAppGame; } //////////////////////////////////////////////////////////////////////// 10.加入下面代码从写简单程序接口的纯虚函数内容 ////////////////////////////////////////////////////////////////////////// CAppGame::CAppGame() { m_hInstance = NULL; m_hWnd = NULL; } CAppGame::~CAppGame() { } // 初始化程序 bool CAppGame::Initialize( HINSTANCE hInstance, HWND hWnd ) { m_hInstance = hInstance; m_hWnd = hWnd; return true; } // 结束程序 void CAppGame::Terminal() { } // 主处理函数 void CAppGame::Process() { } // 主渲染函数 void CAppGame::Render() { } // 主窗口消息处理函数 LRESULT CAppGame::WndProc( UINT message, WPARAM wParam, LPARAM lParam ) { return FALSE; } // 定义Window程序类名函数 const char *CAppGame::WindowClassName() { return "TankBattleCity"; } // 定义Window窗口宽度 const int CAppGame::WindowWidth() { return 800; } // 定义Window窗口高度 const int CAppGame::WindowHeight() { return 600; } // 获得 主程序句柄 HINSTANCE CAppGame::GetInstance() { return m_hInstance; } // 获得 主窗口句柄 HWND CAppGame::GetWnd() { return m_hWnd; } 11.打开WinApp.cpp, 并在 AppInit()函数里做如下修改 // Windows程序初始化 HWND AppInit( HINSTANCE hInstance, int nShowCmd ) { // 程序实例类名 const char *szWindowsClassName = AppEntryClass()->WindowClassName(); static int iWindowWidth = AppEntryClass()->WindowWidth(); // 窗口宽度 static int iWindowHeight = AppEntryClass()->WindowHeight(); // 窗口高度 // 注册窗口类 WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; 12.介绍一点小工具。在Tank项目上加入一个Utility目录 加入FormatString.h 和FormatString.cpp 并加入下面代码 #ifndef __FormatString_H__ #define __FromatString_H__ #include <assert.h> // 格式串垫片函数模版 template <const int iBufLen> inline const char *FormatString( const char *szFormat, ... ) { static char szOutStr[iBufLen]; szOutStr[0] = 0; va_list vl; va_start( vl, szFormat ); vsprintf(szOutStr, szFormat, vl); va_end(vl); assert( strlen(szOutStr) < iBufLen && "Critical Damage" ); return szOutStr; } // 我给出一个常用的缓冲大小为1024字节的宏 #define FSTR FormatString<1024> // 用法: // OutputDebugString( FSTR( "Format Out %s", "ok" ) ); #endif // __FormatString_H__ 我们可以在任何需要输出字符串格式化时使用它 ,这种方法很方便。这个不能用来嵌套调用,也不能用于复杂线程调用,static char szOutStr[iBufLen]; 这是个唯一的内存地址,其他函数调用改变了他的内容就会出错。也就是说用这个工具组合出来的字符串要立即调用。 现在我们项目文件如下图: 第三章 显示图片和基本绘图 这一章我将介绍如何用WindowsGDI显示图片到程序主窗口上,用GDI显示只是为了简单方便,来完成我们的任务,如果要更高效的方法可以使用 DirectX 3D 或 DirectDraw接口。 1. 首先我们准备好下面这张图片我把它放在运行目录RunTime里 取名为ImageC.bmp,接下来就是如何把这张图片显示出来。 2.在Tank项目里加入Render目录,并增加文件 GDIGraphicsDevice.cpp GDIGraphicsDevice.h GDISurface.cpp GDISurface.h GDITextRender.cpp GDITextRender.h 3.打开GDIGraphicsDevice.h 加入下面代码 #ifndef __GDIGraphicsDevice_H__ #define __GDIGraphicsDevice_H__ #include <Windows.h> // 绘图设备,这里指最后能够显示在屏幕上的设备,这是虚拟的, // 我们把它叫做图形设备。 class CGDIGraphicsDevice { public: CGDIGraphicsDevice(); virtual ~CGDIGraphicsDevice(); // 创建设备, 让设备操作对象指向 某个窗口 bool Create( HWND hWnd, int iWidth, int iHeight ); // 释放设备 void Release(); // 更新显示,使主表面内容显示到屏幕上 void UpdateFrame( HDC hdc ); // 获得操作指向的窗口 HWND GetWnd(); protected: // 调整窗口大小 void AdjuestWindowSize( int iWidth, int iHeight ); protected: // 操作指向的窗口句柄 HWND m_hWnd; }; #endif // __GDIGraphicsDevice_H__ 4.打开GDIGraphicsDevice.cpp 加入下面代码 #include "GDIGraphicsDevice.h" CGDIGraphicsDevice::CGDIGraphicsDevice() { m_hWnd = NULL; } CGDIGraphicsDevice::~CGDIGraphicsDevice() { } bool CGDIGraphicsDevice::Create( HWND hWnd, int iWidth, int iHeight ) { return true; } void CGDIGraphicsDevice::Release() { } void CGDIGraphicsDevice::UpdateFrame( HDC hdc ) { } HWND CGDIGraphic
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传
相似文档                                   自信AI助手自信AI助手

当前位置:首页 > 教育专区 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服