你好,和记娱乐的游戏怎么能thinkphp5快速入门门

政府信息公开
重点工作通报
重大决策听证
领导信箱是县委书记、县长在网上开设的网上办事、咨询服务系统。
为加大&走出去&招商力度,吸引更多的客商来祥投资。1月13日至19日,财富工业园区管委…
受委托,我公司于日9:30在祥云县公共资源交易中心1号厅对祥云县公务用车制度改革取消车辆82辆…
----中央政府网站----
中央人民政府门户网站
------中央部门网站------
国家发展和改革委员会
科学技术部
国家民族事务委员会
人力资源和社会保障部
国土资源部
住房和城乡建设部
中国铁路总公司
交通运输部
工业和信息化部
人口计生委
环境保护部
中国民用航空总局
国家广播电影电视总局
国家体育总局
国家统计局
国家工商总局
国家粮食局
国家林业局
国家质检总局
国家安全监管总局
国家知识产权局
国家旅游局
国家新闻出版总署(版权局)
新华通讯社
中国科学院
中国工程院
国务院发展研究中心
中国气象局
中国保险监督管理委员会
国家烟草专卖局
国家外国专家局
国家海洋局
国家测绘局
国家中医药管理局
国家外汇管理局
国务院参事室
国务院机关事务管理局
国务院侨务办公室
国务院法制办
国家行政学院
全国社会保障基金会
国家自然科学基金会
国务院新闻办公室
国家档案局
国家信访局
国家烟草专卖局
国家煤炭安全监察局
国家商用密码管理办公室
国家航天局
国家原子能机构
国务院扶贫办
国务院三峡办
---各省市政府网站---
新疆生产建设兵团
----州市政府网站----
昆明市政府
曲靖市政府
玉溪市政府
昭通市政府
楚雄州政府
红河州政府
丽江市政府
迪庆州政府
文山州政府
版纳州政府
普洱市政府
大理州政府
保山市政府
德宏州政府
怒江州政府
临沧市政府
---县(市)政府网站---
-------网站推荐------
云南兴祥律师事务所
云南电视台
昆明道路交通安全网
云南信息港
云南标准化服务信息网
云南省图书馆
新华网云南
云南招考频道(省招办)
云南省工程建设信息网
云南省毕业生就业信息网
云南工业网
中国中小企业云南网
云南省环境监测网
云南省科技图书文献中心网
云南法制信息网
云南省建设监理协会
云南省红十字会
主办:中共祥云县委
祥云县人民政府
承办:祥云县人民政府办公室
  设计制作:祥云县人民政府办公室电子政务管理中心Windows游戏编程快速入门方法
Windows游戏编程快速入门方法
发布时间: 13:52:17
编辑:www.fx114.net
本篇文章主要介绍了"Windows游戏编程快速入门方法",主要涉及到Windows游戏编程快速入门方法方面的内容,对于Windows游戏编程快速入门方法感兴趣的同学可以参考一下。
&&&&&&&&&&&&&&&&&&&&&&& Windows游戏编程快速入门方法
&&&&&&&&&&&&&&&&&&&&&&& Easideao(简单思路)
&&& 从2001年到2005年,在不知不觉中我已经渡过了4年的职业游戏开发生涯。在这4年里经常会有些网友向我询问编程的入门有没有捷径。每一次我都不知怎么回答才算合适,我也一直想表达一下我的思路和想法,但一直都没有能力把自己的见解在书面上表达出来,其实我认为编写程序并不是很难的事情。最关键的是你对他是否有兴趣,最难的是坚持学习。如果没有兴趣,即使你刚刚入了一点们如果不坚持下去,也是一事无成。
&&& 虽然毅力在学习的过程中有着不可置疑的位置,但是有个合适的方法和适合自己的方法还是很重要的。假如你的兴趣和毅力都过了关,我接下来将以一个游戏的代码编写过程写下来,我坚持写下来,你坚持读完,按照我讲述的步骤去做。我这里不会把所有细节都讲述出来,因为那是太庞大的任务,我的力量无法实现,我们下面的方法就是:我说怎么做,你就怎么做,先知道怎样做一些事情,当你能够按照我说的做出正确的结果说明你已经会了,如果有不懂得再去查看相关资料。
&&& 上面说的有些繁琐,我自己也不太愿意写下去了,我的文笔水平有限,请大家谅解。接下来最重要的就是跟着我做。如果你有什么意见或问题可以给我发E-mail :
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& && 第一章& Windows程序
打开Visual Studio 2003.net ,选择File -& Blank Solution。
在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_hTheA
// 获得主窗口句柄
HWND&&&&&&& GetMainWnd()
&&& return g_hMainW
//////////////////////////////////////////////////////////////////////////
// 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 = hI
&&& // 初始化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.style&&&&&&&&&&& = CS_HREDRAW | CS_VREDRAW;
&&& // 设置主窗口消息处理函数
&&& wc.lpfnWndProc&&&&& = AppWndP
&&& wc.cbClsExtra&&&&&& = 0;
&&& wc.cbWndExtra&&&&&& = 0;
&&& wc.hInstance&&&&&&& = hI
&&& 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&&& = szWindowsClassN
&&& if( !RegisterClass( &wc ) )
&&&&&&& MessageBox( NULL, "RegisterClass - Failed", "Error", MB_OK );
&&& // 创建主窗口
&&& 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 hW
25.编写AppMsgLoop() 的程序主循环
// Windows消息循环和主循环
int AppMsgLoop()
&&& ZeroMemory( &msg, sizeof(MSG) );
&&& // 检测是否有消息要处理
&&& if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
&&&&&&& // 如果接收不到消息表示要退出程序
&&&&&&& if( !GetMessage( &msg, NULL, 0, 0 ) )
&&&&&&&&&&& // 转向结束程序
&&&&&&&&&&& goto _ExitA
&&&&&&& // 执行消息处理
&&&&&&& TranslateMessage( &msg );
&&&&&&& DispatchMessage( &msg );
&&&&&&& // 如果没有任何消息要处理就调用主循环
&&&&&&& Sleep(1);
goto _AppL
&&& AppTerm();
&&& return (int)msg.wP
26.在AppWndProc()函数里加入推出程序消息处理
// Windows消息处理函数
LRESULT CALLBACK AppWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
&&& switch( msg )
&&& case WM_DESTROY:
&&&&&&& PostQuitMessage( 0 );
&&& 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
&&& // 初始化程序
&&& 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 = hI
&&& // 初始化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()
&&& ZeroMemory( &msg, sizeof(MSG) );
&&& // 检测是否有消息要处理
&&& if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
&&&&&&& // 如果接收不到消息表示要退出程序
&&&&&&& if( !GetMessage( &msg, NULL, 0, 0 ) )
&&&&&&&&&&& // 转向结束程序
&&&&&& &&&&&goto _ExitA
&&&&&&& // 执行消息处理
&&&&&&& TranslateMessage( &msg );
&&&&&&& DispatchMessage( &msg );
&&&&&&& // 如果没有任何消息要处理就调用主循环
&&&&&&& AppEntryClass()-&Process();
&&&&&&& Sleep(1);
goto _AppL
& &&AppTerm();
&&& return (int)msg.wP
6.&& 在AppWndProc()函数里加入下面代码
// Windows消息处理函数
LRESULT CALLBACK AppWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
&&& switch( msg )
&&& case WM_DESTROY:
&&&&&&& PostQuitMessage( 0 );
&&& // 调用简单程序接口的消息处理函数,如果返回不是FALSE 就直接完成消息处理
&&& // 否则 继续调用Windows程序默认消息处理函数.
&&& LRESULT lr = AppEntryClass()-&WndProc( msg, wParam, lParam );
&&& if( lr != FALSE )
&&& 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
&&& 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_hI
&&& // 保存主窗口句柄
&&& HWND m_hW
#endif // __AppGame_H__
9.&& 打开AppGame.cpp 加入简单接口程序实例,和获得程序实例的函数
#include "AppGame.h"
// 定义主游戏程序实例
CAppGame theAppG
// 定义获得简单程序接口实例函数,这个在WinApp.cpp中用到,而且必须定义
// 这是Windows程序调用游戏程序的接口
IAppEntry *AppEntryClass()
&&& return &theAppG
////////////////////////////////////////////////////////////////////////
10.加入下面代码从写简单程序接口的纯虚函数内容
//////////////////////////////////////////////////////////////////////////
CAppGame::CAppGame()
&&& m_hInstance = NULL;
&&& m_hWnd = NULL;
CAppGame::~CAppGame()
// 初始化程序
bool CAppGame::Initialize( HINSTANCE hInstance, HWND hWnd )
&&& m_hInstance = hI
&&& m_hWnd = hW
// 结束程序
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_hI
// 获得 主窗口句柄
HWND CAppGame::GetWnd()
&&& return m_hW
&&&& 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.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_start( vl, szFormat );
&&& vsprintf(szOutStr, szFormat, vl);
&&& va_end(vl);
&&& assert( strlen(szOutStr) & iBufLen && "Critical Damage" );
&&& return szOutS
// 我给出一个常用的缓冲大小为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
&&& 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_hW
#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 )
void CGDIGraphicsDevice::Release()
void CGDIGraphicsDevice::UpdateFrame( HDC hdc )
HWND CGDIGraphicsDevice::GetWnd()
&&& return m_hW
//////////////////////////////////////////////////////////////////////////
// 调整窗口大小 使绘图区域等于 iWidth iHeight 指示的大小
void CGDIGraphicsDevice::AdjuestWindowSize( int iWidth, int iHeight )
&&&&& 5.实现调整窗口大小函数
// 调整窗口大小 使绘图区域等于 iWidth iHeight 指示的大小
void CGDIGraphicsDevice::AdjuestWindowSize( int iWidth, int iHeight )
&&& // 定义窗口在屏幕上的位置 和 窗口显示区位置
&&& RECT rcScreen,rcC
&&& // 获得窗口在屏幕上的位置 和 窗口显示区位置
&&& GetWindowRect( m_hWnd, &rcScreen );
&&& GetClientRect( m_hWnd, &rcClient );
&&& // 计算两个区域的宽和高
&&& int rScreenWidth&&& = rcScreen.right - rcScreen.left + 1;
&&& int rScreenHeight&& = rcScreen.bottom - rcScreen.top + 1;
&&& int rClientWidth&&& = rcClient.right - rcClient.left + 1;
&&& int rClientHeight&& = rcClient.bottom - rcClient.top + 1;
&&& // 计算两个区域的大小差
&&& int rW = rScreenWidth&& - rClientW
&&& int rH = rScreenHeight& - rClientH
&&& // 计算出新窗口大小
&&& rcScreen.right& =&& iWidth& + rW;
&&& rcScreen.bottom =&& iHeight + rH;
&&& // 设置窗口大小
&&& SetWindowPos( m_hWnd,NULL,rcScreen.left, rcScreen.top, rcScreen.right,rcScreen.bottom,SWP_FRAMECHANGED );
&&& // 显示出Windows
&&& ShowWindow( m_hWnd, SW_SHOW );
&&& // 更新窗口
&&& UpdateWindow( m_hWnd );
&&&&& 6.实现创建设备函数
// 创建设备, 让设备操作对象指向 某个窗口
bool CGDIGraphicsDevice::Create( HWND hWnd, int iWidth, int iHeight )
&&& // 保存窗口句柄
&&& m_hWnd = hW
&&& // 调整显示区大小
&&& AdjuestWindowSize( iWidth, iHeight );
&&&&& 7.打开GDISurface.h 输入下面代码
#ifndef __GDISurface_H__
#define __GDISurface_H__
#include &windows.h&
class CGDIGraphicsD
// 表面类 用来存放一个图片,并用来显示图片
class CGDISurface
&&& // 位块传送方式
&&& enum SurfaceBltMode
&&&&&&& BLT_BLOCK,&&&&&&&&& // 复制方式, 完全显示在目标上
&&&&&&& BLT_ALPHATEST,&&&&& // 透明色检测方式, 如果遇到 RGB( 0, 0, 255 ) 图片里的纯蓝色就跳过
&&&&&&& BLT_ALPHABLEND,&&&& // 未支持
&&& CGDISurface();
&&& virtual ~CGDISurface();
&&& // 创建一个位图
&&& bool Create( CGDIGraphicsDevice *pDevice, int iWidth, int iHeight );
&&& // 从文件读取一个位图
&&& bool LoadBmp( CGDIGraphicsDevice *pDevice, const char *szFileName );
&&& // 释放位图
&&& void Release();
&&& // 获得宽
&&& int GetWidth();
&&& // 获得高
&&& int GetHeight();
&&& // 获得位图设备句柄
&&& HDC GetDC();
&&& // 获得透明通道位图设备句柄
&&& HDC GetMaskDC();
&&& // 清除表面为 某种颜色
&&& void Clear( COLORREF c = RGB( 0, 0, 0 ) );
&&& // 画店
&&& void SetPixel( int x, int y, COLORREF c );
&&& // 画线
&&& void Line( int x1, int y1, int x2, int y2, COLORREF c );
&&& // 画矩形
&&& void Rect( int x1, int y1, int x2, int y2, COLORREF c );
&&& // 位图传送
&&& void Blt( CGDISurface *pSurface, int x, int y, int rx, int ry, int w, int h, SurfaceBltMode sbmMode );
protected:
&&& // 表面宽度
&&& int m_iW
&&& // 表面高度
&&& int m_iH
&&& // 位图句柄
&&& HBITMAP m_hB
&&& // 位图透明通道图句柄
&&& HBITMAP m_hMaskB
&&& // 保存两种位图句柄
&&& HBITMAP m_hOldB
&&& HBITMAP m_hOldMaskB
&&& // 两个用来显示的设备句柄
&&& // 位图设备句柄
&&& HDC m_hDC;&&&&&&&&&&&&&&&&&
&&& // 透明通道位图设备句柄
&&& HDC m_hMaskDC;
#endif // __GDISurface_H__
&&&& 8.打开GDISurface.cpp 输入下面代码
#include "GDISurface.h"
#include "GDIGraphicsDevice.h"
CGDISurface::CGDISurface()
&&& m_iWidth&&&&&&&&&&& = 0;
&&& m_iHeight&&&&&&&&&& = 0;
&&& m_hBitmap&&&&&&&&&& = NULL;
&&& m_hMaskBitmap&&&&&& = NULL;
&&& m_hOldBitmap&&&&&&& = NULL;
&&& m_hOldMaskBitmap&&& = NULL;
&&& m_hDC&&&&&&&&&&&&&& = NULL;&&&&&&&&&&&&&&&&&
&&& m_hMaskDC&&&&&&&&&& = NULL;
CGDISurface::~CGDISurface()
// 创建一个位图
bool CGDISurface::Create( CGDIGraphicsDevice *pDevice, int iWidth, int iHeight )
// 从文件读取一个位图
bool CGDISurface::LoadBmp( CGDIGraphicsDevice *pDevice, const char *szFileName )
// 释放位图
void CGDISurface::Release()
int CGDISurface::GetWidth()
&&& return m_iW
int CGDISurface::GetHeight()
&&& return m_iH
// 获得位图设备句柄
HDC CGDISurface::GetDC()
&&& return m_hDC;
// 获得透明通道位图设备句柄
HDC CGDISurface::GetMaskDC()
&&& return m_hMaskDC;
// 清除表面为 某种颜色
void CGDISurface::Clear( COLORREF c )
void CGDISurface::SetPixel( int x, int y, COLORREF c )
void CGDISurface::Line( int x1, int y1, int x2, int y2, COLORREF c )
void CGDISurface::Rect( int x1, int y1, int x2, int y2, COLORREF c )
// 位图传送
void CGDISurface::Blt( CGDISurface *pSurface, int x, int y, int rx, int ry, int w, int h, BltMode iMode )
10.&&&&&&&&&& 实现创建位图
// 创建一个位图
bool CGDISurface::Create( CGDIGraphicsDevice *pDevice, int iWidth, int iHeight )
&&& // 获得主窗口绘图设备句柄
&&& HWND hWnd = pDevice-&GetWnd();
&&& HDC hdcWindow = ::GetDC( hWnd );
&&& // 创建图形设备句柄
&&& m_hDC&&&&&& = ::CreateCompatibleDC( hdcWindow );
&&& m_hMaskDC&& = ::CreateCompatibleDC( hdcWindow );
&&& // 创建位图和透明位图
&&& m_hBitmap&&&&&& = ::CreateCompatibleBitmap( hdcWindow, iWidth, iHeight );
&&& m_hMaskBitmap&& = ::CreateBitmap( iWidth, iHeight, 1, 1, NULL );
&&& // 关联设备和位图句柄
&&& m_hOldBitmap&&&&&&& = (HBITMAP)::SelectObject( m_hDC, m_hBitmap );
&&& m_hOldMaskBitmap&&& = (HBITMAP)::SelectObject( m_hMaskDC, m_hMaskBitmap );
&&& // 制作透明通道位图
&&& ::SetBkColor( m_hDC, RGB(0,0,255) );
&&& ::BitBlt( m_hMaskDC, 0, 0, iWidth, iHeight, m_hDC, 0, 0, SRCCOPY );
&&& ::SetBkColor( m_hDC, RGB(0,0,0) );
&&& ::SetTextColor( m_hDC, RGB(255,255,255) );
&&& ::BitBlt( m_hDC, 0, 0, iWidth, iHeight, m_hMaskDC, 0, 0, SRCAND );
&&& // 释放主窗口绘图句柄
&&& ::ReleaseDC( hWnd, hdcWindow );
&&& // 保存表面大小
&&& m_iWidth&&& = iW
&&& m_iHeight&& = iH
11.&&&&&&&&&& 实现从文件读取位图, 方法和创建位图类似,只是原位图从文件用LoadImage读入。
// 从文件读取一个位图
bool CGDISurface::LoadBmp( CGDIGraphicsDevice *pDevice, const char *szFileName )
&&& // 读取位图文件信息,确定位图大小
&&& FILE *fp = fopen( szFileName, "rb" );
&&& if( NULL == fp )
&&&&&&& OutputDebugString( FSTR( "Open bmp file [%s] failed(%s:%d)", szFileName, __FILE__, __LINE__ ) );
&&& BITMAPFILEHEADER
&&& BITMAPINFOHEADER
&&& fread( &bmfh, sizeof(BITMAPFILEHEADER), 1, fp );
&&& fread( &bmih, sizeof(BITMAPINFOHEADER), 1, fp );
&&& fclose(fp);
&&& // 如果不是位图则返回失败
&&& if( bmfh.bfType != 0x4D42 )
&&&&&&& OutputDebugString( FSTR( "the bmp file [%s] type is failed(%s:%d)", szFileName, __FILE__, __LINE__ ) );
&&& HBITMAP hBmp = (HBITMAP)::LoadImage(NULL, szFileName, IMAGE_BITMAP, bmih.biWidth, bmih.biHeight, LR_LOADFROMFILE | LR_CREATEDIBSECTION );
&&& m_iWidth&&& = bmih.biW
&&& m_iHeight&& = bmih.biH
&&& HWND hWnd = pDevice-&GetWnd();
&&& HDC hdcWindow = ::GetDC( hWnd );
&&& m_hBitmap&&&&&& = ::CreateCompatibleBitmap( hdcWindow, m_iWidth, m_iHeight );
&&& m_hMaskBitmap&& = ::CreateBitmap( m_iWidth, m_iHeight, 1, 1, NULL );
&&& HDC hTempDC = ::CreateCompatibleDC( hdcWindow );
&&& m_hDC&&&&&& = ::CreateCompatibleDC( hdcWindow );
&&& m_hMaskDC&& = ::CreateCompatibleDC( hdcWindow );
&&& HBITMAP hOldBitmap& = (HBITMAP)::SelectObject( hTempDC, hBmp );
&&& m_hOldBitmap&&&&&&& = (HBITMAP)::SelectObject( m_hDC, m_hBitmap );
&&& m_hOldMaskBitmap&&& = (HBITMAP)::SelectObject( m_hMaskDC, m_hMaskBitmap );
&&& ::BitBlt( m_hDC, 0, 0, m_iWidth, m_iHeight, hTempDC, 0, 0, SRCCOPY );
&&& ::SetBkColor( m_hDC, RGB(0,0,255) );
&&& ::BitBlt( m_hMaskDC, 0, 0, m_iWidth, m_iHeight, m_hDC, 0, 0, SRCCOPY );
&&& ::SetBkColor( m_hDC, RGB(0,0,0) );
&&& ::SetTextColor( m_hDC, RGB(255,255,255) );
&&& ::BitBlt( m_hDC, 0, 0, m_iWidth, m_iHeight, m_hMaskDC, 0, 0, SRCAND );
&&& ::SelectObject( hTempDC, hOldBitmap );
&&& DeleteDC( hTempDC );
&&& DeleteObject( hBmp );
&&& ::ReleaseDC( hWnd, hdcWindow );
12.&&&&&&&&&& 实现释放位图
// 释放位图
void CGDISurface::Release()
&&& ::SelectObject( m_hDC, m_hOldBitmap );
&&& ::SelectObject( m_hMaskDC, m_hOldMaskBitmap );
&&& ::DeleteDC( m_hMaskDC );
&&& ::DeleteDC( m_hDC );
&&& ::DeleteObject( m_hBitmap );
&&& ::DeleteObject( m_hMaskBitmap );
13.&&&&&&&&&& 实现4个基本绘图操作
// 清除表面为 某种颜色
void CGDISurface::Clear( COLORREF c )
&&& // 创建填充画笔
&&& HBRUSH hBrush = CreateSolidBrush( c );
&&& // 填充整个表面
&&& RECT rect = { 0, 0, m_iWidth, m_iHeight };
&&& FillRect( m_hDC, &rect, hBrush );
&&& // 释放画笔
&&& DeleteObject( hBrush );
void CGDISurface::SetPixel( int x, int y, COLORREF c )
&&& ::SetPixel( m_hDC, x, y, c );
void CGDISurface::Line( int x1, int y1, int x2, int y2, COLORREF c )
&&& HPEN hPen = CreatePen(PS_SOLID, 1, c );
&&& HPEN hOldPen = SelectPen( m_hDC, hPen );
&&& MoveToEx( m_hDC, x1, y1, (LPPOINT) NULL );
&&& LineTo( m_hDC, x2, y2 );
&&& SelectPen( m_hDC, hOldPen );
&&& DeletePen( hPen );
void CGDISurface::Rect( int x1, int y1, int x2, int y2, COLORREF c )
&&& // 画4条线 矩形边框
&&& Line( x1, y1, x2, y1, c );
&&& Line( x1, y2, x2, y2, c );
&&& Line( x1, y1, x1, y2, c );
&&& Line( x2, y1, x2, y2, c );
14.&&&&&&&&&& 实现位图传送功能
// 位图传送
void CGDISurface::Blt( CGDISurface *pSurface, int x, int y, int rx, int ry, int w, int h, BltMode iMode )
&&& HDC hdcDst = pSurface-&GetDC();
&&& switch( iMode )
&&& case BLT_BLOCK:
&&&&&&& // 基本复制方式传送位图
&&&&&&& BitBlt( hdcDst, x, y, w, h, m_hDC, rx, ry, SRCCOPY );
&&& case BLT_ALPHATEST:
&&&&&&& // 带透明色方式传送位图
&&&&&&& SetBkColor( hdcDst, RGB(255,255,255) );
&&&&&&& SetTextColor( hdcDst, RGB(0,0,0) );
&&&&&&& BitBlt( hdcDst, x, y, w, h, m_hMaskDC, rx, ry, SRCAND );
&&&&&&& BitBlt( hdcDst, x, y, w, h, m_hDC, rx, ry, SRCPAINT );
&&& case BLT_ALPHABLEND:
15.&&&&&&&&&& 打开GDIGraphicsDevice.h 加入下面代码
#ifndef __GDIGraphicsDevice_H__
#define __GDIGraphicsDevice_H__
#include &Windows.h&
class CGDIS
// 绘图设备,这里指最后能够显示在屏幕上的设备,这是虚拟的,
// 我们把它叫做图形设备。
class CGDIGraphicsDevice
&&& CGDIGraphicsDevice();
&&& virtual ~CGDIGraphicsDevice();
&&& // 创建设备, 让设备操作对象指向 某个窗口
&&& bool Create( HWND hWnd, int iWidth, int iHeight );
&&& // 释放设备
&&& void Release();
&&& // 更新显示,使主表面内容显示到屏幕上
&&& void UpdateFrame( HDC hdc );
&&& // 获得操作指向的窗口
&&& HWND GetWnd();
&&& // 获得主表面
&& &CGDISurface *GetMainSurface();
protected:
&&& // 调整窗口大小
&&& void AdjuestWindowSize( int iWidth, int iHeight );
protected:
&&& // 操作指向的窗口句柄
&&& HWND m_hW
&&& // 住缓冲表面
&&& CGDISurface *m_pMainS
#endif // __GDIGraphicsDevice_H__
16.&&&&&&&&&& 打开GDIGraphicsDevice.cpp 修改和增加下面代码
#include "GDIGraphicsDevice.h"
#include "GDISurface.h"
CGDIGraphicsDevice::CGDIGraphicsDevice()
&&& m_hWnd = NULL;
&&& m_pMainSurface = NULL;
CGDIGraphicsDevice::~CGDIGraphicsDevice()
// 创建设备, 让设备操作对象指向 某个窗口
bool CGDIGraphicsDevice::Create( HWND hWnd, int iWidth, int iHeight )
&&& // 保存窗口句柄
&&& m_hWnd = hW
&&& // 调整显示区大小
&&& AdjuestWindowSize( iWidth, iHeight );
&&& m_pMainSurface = new CGDISurface();
// 释放设备
void CGDIGraphicsDevice::Release()
&&& delete m_pMainS
&&& m_pMainSurface = NULL;
17.&&&&&&&&&& 增加获取主表面函数
// 获得主表面
CGDISurface *CGDIGraphicsDevice::GetMainSurface()
&&& return m_pMainS
18.&&&&&&&&&& 增加创建主表面
// 创建设备, 让设备操作对象指向 某个窗口
bool CGDIGraphicsDevice::Create( HWND hWnd, int iWidth, int iHeight )
&&& // 保存窗口句柄
&&& m_hWnd = hW
&&& // 调整显示区大小
&&& AdjuestWindowSize( iWidth, iHeight );
&&& m_pMainSurface = new CGDISurface();
&&& if( !m_pMainSurface-&Create( this, iWidth, iHeight ) )
&&&&&&& OutputDebugString( FSTR( "GraphicsDevice Create Main Surface Failed" ) );
// 释放设备
void CGDIGraphicsDevice::Release()
&&& m_pMainSurface-&Release();
&&& delete m_pMainS
&&& m_pMainSurface = NULL;
19.&&&&&&&&&& 增加更新显示函数功能
// 更新显示,使主表面内容显示到屏幕上
void CGDIGraphicsDevice::UpdateFrame( HDC hdc )
&&& // 如果主表面没有创建成功就返回
&&& if( NULL == m_pMainSurface )
&&& HDC hdcSrc = m_pMainSurface-&GetDC();
&&& int iWidth& = m_pMainSurface-&GetWidth();
&&& int iHeight = m_pMainSurface-&GetHeight();
&&& // 更新显示到屏幕,将由 WM_PAINT 调用
&&& BitBlt( hdc, 0, 0, iWidth, iHeight, hdcSrc, 0, 0, SRCCOPY );
20.&&&&&&&&&& 为了方便我们在项目Tank上加入一个全局数据定义文件,大家可以在此定义非常公用或重要的全局变量。并加入两个文件 ShareData.h ShareData.cpp
21.&&&&&&&&&& 打开ShareData.h 加入下面代码
#ifndef __ShareData_H__
#define __ShareData_H__
#include "GDIGraphicsDevice.h"
#include "GDISurface.h"
#include "GDITextRender.h"
extern CGDIGraphicsDevice *theGraphicsD
#endif // __ShareData_H__
22.&&&&&&&&&& 打开ShareData.cpp 加入下面代码
#include "ShareData.h"
CGDIGraphicsDevice *theGraphicsDevice = NULL;
23.&&&&&&&&&& 打开AppGame.cpp里加入下面代码
#include "AppGame.h"
#include "ShareData.h"
CGDISurface theS
// 定义主游戏程序实例
CAppGame theAppG
24.&&&&&&&&&& 加入下面代码,创建
// 初始化程序
bool CAppGame::Initialize( HINSTANCE hInstance, HWND hWnd )
&&& m_hInstance = hI
&&& m_hWnd = hW
&&& // 创建图形设备
&&& theGraphicsDevice = new CGDIGraphicsDevice();
&&& if( !theGraphicsDevice-&Create( m_hWnd, WindowWidth(), WindowHeight() ) )
&&&&&&& OutputDebugString( "Create GraphicsDevice Failed" );
&&& // 读取位图
&&& if( !theSurface.LoadBmp( theGraphicsDevice, "ImageC.bmp" ) )
&&&&&&& OutputDebugString( "Load bitmap Failed" );
// 结束程序
void CAppGame::Terminal()
&&& // 释放位图
&&& theSurface.Release();
&&& // 释放图形设备
&&& theGraphicsDevice-&Release();
&&& delete theGraphicsD
25.& 修改下面代码来显示读入的图片
// 主处理函数
void CAppGame::Process()
&&& Render();
// 主渲染函数
void CAppGame::Render()
&&& // 显示位图
&&& theSurface.Blt( theGraphicsDevice-&GetMainSurface(), 0, 0, 0, 0, WindowWidth(), WindowHeight(), CGDISurface::BLT_BLOCK );
26.&&&&&&&&&& 在消息处理函数里加入更新显示代码
// 主窗口消息处理函数
LRESULT CAppGame::WndProc( UINT message, WPARAM wParam, LPARAM lParam )
&&& PAINTSTRUCT
&&& switch( message )
&&& case WM_PAINT:
&&&&&&&&&&& hdc = BeginPaint( m_hWnd, &ps );
&&&&&&&&&&& if( theGraphicsDevice )
&&&&&&&&&&& {
&&&&&&&&&&&&&&& // 调用图形设备更新显示
&&&&&&&&&&&&&&& theGraphicsDevice-&UpdateFrame( hdc );
&&&&&&&&&&& }
&&&&&&&&&&& EndPaint( m_hWnd, &ps );
&&&&&&& return TRUE;
&&& case WM_ERASEBKGND:
&&&&&&& return TRUE;
&&& return FALSE;
27.&&&&&&&&&& 在CAppGame::Render()里加入更新显示通知
// 主渲染函数
void CAppGame::Render()
&&& // 显示位图
&&& theSurface.Blt( theGraphicsDevice-&GetMainSurface(), 0, 0, 0, 0, WindowWidth(), WindowHeight(), CGDISurface::BLT_BLOCK );
&&& // 通知Window程序更新显示窗口
&&& RECT rcW
&&& GetClientRect( m_hWnd, &rcWindow );
&&& RedrawWindow( m_hWnd, &rcWindow, NULL, RDW_INVALIDATE );
28.&&&&&&&&&& 运行程序可以看到如下效果
29.在CAppGame::Render() 里加入下面代码
// 主渲染函数
void CAppGame::Render()
&& &// 清除主表面
&&& theGraphicsDevice-&GetMainSurface()-&Clear( RGB( 125,0, 23 ) );
&&& // 显示位图
&&& theSurface.Blt( theGraphicsDevice-&GetMainSurface(), 0, 0, 0, 0, WindowWidth(), WindowHeight(), CGDISurface::BLT_BLOCK );
&&& // 通知Window程序更新显示窗口
&&& RECT rcW
&&& GetClientRect( m_hWnd, &rcWindow );
&&& RedrawWindow( m_hWnd, &rcWindow, NULL, RDW_INVALIDATE );
大家可以看到下面效果
30.将CAppGame::Render() 修改为
void CAppGame::Render()
&&& // 清除主表面
&&& theGraphicsDevice-&GetMainSurface()-&Clear( RGB( 125,0, 23 ) );
&&& // 显示位图
&&& theSurface.Blt( theGraphicsDevice-&GetMainSurface(), 0, 0, 0, 0, WindowWidth(), WindowHeight(), CGDISurface::BLT_ALPHATEST );
&&& // 通知Window程序更新显示窗口
&&& RECT rcW
&&& GetClientRect( m_hWnd, &rcWindow );
&&& RedrawWindow( m_hWnd, &rcWindow, NULL, RDW_INVALIDATE );
可以看到如下效果
蓝色已经没有了,绘制方式改为透明方式。
31.我们将theSurface 改为 theImageC 并且放到ShareData.cpp 中定义 以便以后使用方便
// 初始化程序
bool CAppGame::Initialize( HINSTANCE hInstance, HWND hWnd )
&&& m_hInstance = hI
&&& m_hWnd = hW
&&& // 创建图形设备
&&& theGraphicsDevice = new CGDIGraphicsDevice();
&&& if( !theGraphicsDevice-&Create( m_hWnd, WindowWidth(), WindowHeight() ) )
&&&&&&& OutputDebugString( "Create GraphicsDevice Failed" );
&&& // 读取位图
&&& theImageC = new CGDISurface();
&&& if( !theImageC-&LoadBmp( theGraphicsDevice, "ImageC.bmp" ) )
&&&&&&& OutputDebugString( "Load bitmap Failed" );
// 结束程序
void CAppGame::Terminal()
&&& // 释放位图
&&& theImageC-&Release();
&&& delete theImageC;
&&& theImageC = NULL;
&&& // 释放图形设备
&&& theGraphicsDevice-&Release();
&&& delete theGraphicsD
&&& theGraphicsDevice = NULL;
// 主处理函数
void CAppGame::Process()
&&& Render();
// 主渲染函数
void CAppGame::Render()
&&& // 清除主表面
&&& theGraphicsDevice-&GetMainSurface()-&Clear( RGB( 125,0, 23 ) );
&&& // 显示位图
&&& theImageC-&Blt( theGraphicsDevice-&GetMainSurface(), 0, 0, 0, 0, WindowWidth(), WindowHeight(), CGDISurface::BLT_ALPHATEST );
&&& // 通知Window程序更新显示窗口
& &&RECT rcW
&&& GetClientRect( m_hWnd, &rcWindow );
&&& RedrawWindow( m_hWnd, &rcWindow, NULL, RDW_INVALIDATE );
第四章& 文字显示 计时器 刷新率
&&&&&&&&&&& 在编写程序时有些很重要的信息要显示出来,帮助调试程序,其中显示文字处于非常重要的位置。计时器我们将用到系统函数timeGetTime(),它是用来获得系统从开始到现在所经历的毫秒数,记录一个开始时间,然后不断判断现在的时间和开始时间的间隔,以达到控制某一段代码以一定的频率执行。刷新率是表示在一秒钟之内更新显示了多少次,最后我们把它显示在屏幕上。
&&&&&&&&&&&
1.&&&&&&&&&&& 打开GDITextRender.h 输入下面代码
#ifndef __GDITextRender_H__
#define __GDITextRender_H__
#include &windows.h&
class CGDIS
// 文字显示类
class CGDITextRender
&&& CGDITextRender();
&&& virtual ~CGDITextRender();
&&& // 创建字体
&&& bool Create( PLOGFONT pFont );
&&& // 释放
&&& void Release();
&&& // 向表面输出文字
&&& void TextOut( CGDISurface *pSurface, int x, int y, const char *szString, COLORREF c, int len = 0 );
protected:
&&& // 字体句柄
&&& HFONT m_hF
#endif // __GDITextRender_H__
2.&&&&&&&&&&& 打开GDITextRender.cpp 输入下面代码
#include "GDITextRender.h"
CGDITextRender::CGDITextRender()
&&& m_hFont = NULL;
CGDITextRender::~CGDITextRender()
// 创建字体
bool CGDITextRender::Create( PLOGFONT pFont )
void CGDITextRender::Release()
// 向表面输出文字
void CGDITextRender::TextOut( CGDISurface *pSurface, int x, int y, const char *szString, COLORREF c, int len )
3.&&&&&&&&&&& 实现创建字体功能
// 创建字体
bool CGDITextRender::Create( PLOGFONT pFont )
&&& // 创建 pFont 指定的字体
&&& m_hFont = CreateFont(
&&&&&&& pFont-&lfHeight,
&&&&&&& pFont-&lfWidth,
&&&&&&& pFont-&lfEscapement,
&&&&&&& pFont-&lfOrientation,
&&&&&&& pFont-&lfWeight,
&&&&&&& pFont-&lfItalic,
&&&&&&& pFont-&lfUnderline,
&&&&&&& pFont-&lfStrikeOut,
&&&&&&& pFont-&lfCharSet,
&&&&&&& pFont-&lfOutPrecision,
&&&&&&& pFont-&lfClipPrecision,
&&&&&&& pFont-&lfQuality,
&&&&&&& pFont-&lfPitchAndFamily,
&&&&&&& pFont-&lfFaceName );
&&& if( m_hFont == NULL )
&&&&&&& OutputDebugString( FSTR( "Create Font Failed: %s %d/n", pFont-&lfFaceName, pFont-&lfHeight ) );
4.实现释放字体
void CGDITextRender::Release()
&&& // 如果字体已经创建
&&& if( m_hFont )
&&&&&&& // 删除字体句柄
&&&&&&& DeleteObject( m_hFont );
& &&&&&&m_hFont = NULL;
5.修改文字输出函数,加入输出文字功能
#include "GDITextRender.h"
#include "GDISurface.h"
#include "FormatString.h"
#include &windowsx.h&
// 向表面输出文字
void CGDITextRender::TextOut( CGDISurface *pSurface, int x, int y, const char *szString, COLORREF c, int len )
&&& // 如果指定的字符串长度是0
&&& if( len == 0 )
&&&&&&& // 自动获取字符串长度
&&&&&&& len = (int)strlen( szString );
&&& // 获得表面设备句柄
&&& HDC hdc = pSurface-&GetDC();
&&& // 选择字体
&&& HFONT hOldFont = SelectFont( hdc, m_hFont );
&&& // 显示文字
&&& SetBkMode( hdc, TRANSPARENT );
&&& SetBkColor( hdc, RGB(0,0,0) );
&&& SetTextColor( hdc, c );
&&& ::TextOut( hdc, x, y, szString, len );
&&& // 恢复字体
&&& SelectFont( hdc, hOldFont );
6.打开ShareData.h 加入下面代码
#ifndef __ShareData_H__
#define __ShareData_H__
#include "GDIGraphicsDevice.h"
#include "GDISurface.h"
#include "GDITextRender.h"
extern CGDIGraphicsDevice *theGraphicsD
extern CGDISurface *theImageC;
extern CGDITextRender *theTextR
#endif // __ShareData_H__
7.打开ShareData.cpp 加入下面代码
#include "ShareData.h"
CGDIGraphicsDevice *theGraphicsDevice = NULL;
CGDISurface *theImageC = NULL;
CGDITextRender *theTextRender = NULL;
8.打开AppGame.cpp 加入 初始化文字输出功能 和释放
// 初始化程序
bool CAppGame::Initialize( HINSTANCE hInstance, HWND hWnd )
&& &m_hInstance = hI
&&& m_hWnd = hW
&&& // 创建图形设备
&&& theGraphicsDevice = new CGDIGraphicsDevice();
&&& if( !theGraphicsDevice-&Create( m_hWnd, WindowWidth(), WindowHeight() ) )
&&&&&&& OutputDebugString( "Create GraphicsDevice Failed" );
&&& // 读取位图
&&& theImageC = new CGDISurface();
&&& if( !theImageC-&LoadBmp( theGraphicsDevice, "ImageC.bmp" ) )
&&&&&&& OutputDebugString( "Load bitmap Failed" );
&&& // 初始化文字输出功能
&& &LOGFONT FontInfo = { 16, 0, 0, 0,
&&&&&&& FW_NORMAL, FALSE, FALSE, FALSE,
&&&&&&& DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
&&&&&&& CLIP_DEFAULT_PRECIS,
&&&&&&& DEFAULT_QUALITY,
&&&&&&& VARIABLE_PITCH,
&&&&&&& "宋体" };
&&& theTextRender = new CGDITextRender();
&&& if( !theTextRender-&Create( &FontInfo ) )
&&&&&&& OutputDebugString( "Create theTextRender Failed/n" );
// 结束程序
void CAppGame::Terminal()
&&& // 释放文字输出功能
&&& theTextRender-&Release();
&&& delete theTextR
&&& theTextRender = NULL;
&&& // 释放位图
&&& theImageC-&Release();
&&& delete theImageC;
&&& theImageC = NULL;
&&& // 释放图形设备
&&& theGraphicsDevice-&Release();
&&& delete theGraphicsD
&&& theGraphicsDevice = NULL;
9.在CAppGame::Render()函数里做如下修改来测试文字输出功能
// 主渲染函数
void CAppGame::Render()
&&& CGDISurface *pScreen = theGraphicsDevice-&GetMainSurface();
&&& // 清除主表面
&&& pScreen-&Clear( RGB( 125,0, 23 ) );
&&& // 显示位图
&&& theImageC-&Blt( pScreen, 0, 0, 0, 0, WindowWidth(), WindowHeight(), CGDISurface::BLT_ALPHATEST );
&&& // 显示文字
&&& theTextRender-&TextOut( pScreen, 0, 0, "测试文字ABC", RGB( 255, 255, 255 ) );
&&& // 通知Window程序更新显示窗口
&&& RECT rcW
&&& GetClientRect( m_hWnd, &rcWindow );
&&& RedrawWindow( m_hWnd, &rcWindow, NULL, RDW_INVALIDATE );
看到如下结果
&&&&&&&&&&& 10.在Tank项目Utility目录里加入Fps.cpp Fps.h
&&&&&&&&&&&
&&&&&&&&&&& 11.打开Fps.h 输入下面代码
#ifndef __Fps_H__
#define __Fps_H__
#include &WTypes.h&
class CFps
&&& CFps();
&&& virtual ~CFps();
&&& // 统计, 没掉一次 计数器加1 并判断 是否该计算FPS
&&& void Count();
&&& // 获得FPS
&&& int GetFps();
protected:
&&& // 记录刷新率
&&& int m_iF
&&& // 统计次数
&&& int m_iC
&&& // 上一次记录FPS的时间
&&& DWORD m_dwPrevRecordFpsT
&&& // 计算FPS时间间隔
&&& DWORD m_dwRecordFpsI
#endif // __Fps_H__
&&&&&&&&&&& 12.打开Fps.cpp 输入下面代码
#include "Fps.h"
#include &mmsystem.h&
#pragma comment( lib, "winmm.lib" )
CFps::CFps()
&&& m_iCount = 0;
&&& m_iFps = 0;
&&& m_dwPrevRecordFpsTime = 0;
&&& m_dwRecordFpsInterval = 1000; // 1秒钟记录一次
CFps::~CFps()
void CFps::Count()
&&& // 没调用一次就加1
&&& m_iCount++;
&&& // 如果时间已经过去1000毫秒
&&& if( timeGetTime() - m_dwPrevRecordFpsTime &= m_dwRecordFpsInterval )
&&&&&&& // 记录1秒钟调用次数
&&&&&&& m_iFps = m_iC
&&&&&&& // 复位计数器
&&&&&&& m_iCount = 0;
&&&&&&& // 复位开始计时时间
&&&&&&& m_dwPrevRecordFpsTime = timeGetTime();
int CFps::GetFps()
&&& return m_iF
&&&&&&&&&&& 13.在ShareData.h 和 ShareData.cpp 中分别加入下面代码
ShareData.h :
#ifndef __ShareData_H__
#define __ShareData_H__
#include "GDIGraphicsDevice.h"
#include "GDISurface.h"
#include "GDITextRender.h"
#include "Fps.h"
extern CGDIGraphicsDevice *theGraphicsD
extern CGDISurface *theImageC;
extern CGDITextRender *theTextR
extern CFps *theRenderF
#endif // __ShareData_H__
ShareData.cpp :
#include "ShareData.h"
CGDIGraphicsDevice *theGraphicsDevice = NULL;
CGDISurface *theImageC = NULL;
CGDITextRender *theTextRender = NULL;
CFps *theRenderFps = NULL;
&&&&&&&&&&& 14.在AppGame.cpp 中 CAppGame::Initialize() 和 CAppGame::Terminal()中加入下面代码
&&& theTextRender = new CGDITextRender();
&&& if( !theTextRender-&Create( &FontInfo ) )
&&&&&&& OutputDebugString( "Create theTextRender Failed/n" );
&&& // 创建渲染刷新率统计器
&&& theRenderFps = new CFps();
// 结束程序
void CAppGame::Terminal()
&&& // 释放渲染刷新率统计器
&&& delete theRenderF
&&& // 释放文字输出功能
&&& theTextRender-&Release();
&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&& 15.在 CAppGame::Render() 函数里加入 刷新率统计,并显示在屏幕上,并在
AppGame.cpp 最上加入 #include “FormatString.h”
// 主渲染函数
void CAppGame::Render()
&&& CGDISurface *pScreen = theGraphicsDevice-&GetMainSurface();
&&& // 清除主表面
&&& pScreen-&Clear( RGB( 127,127, 127 ) );
&&& // 显示位图
&&& //theImageC-&Blt( pScreen, 0, 0, 0, 0, WindowWidth(), WindowHeight(), CGDISurface::BLT_ALPHATEST );
&&& // 显示文字
&&& theTextRender-&TextOut( pScreen, 0, 0, FSTR( "FPS = %2d", theRenderFps-&GetFps() ), RGB( 255, 255, 255 ) );
&&& // 通知Window程序更新显示窗口
&&& RECT rcW
&&& GetClientRect( m_hWnd, &rcWindow );
&&& RedrawWindow( m_hWnd, &rcWindow, NULL, RDW_INVALIDATE );
&&& theRenderFps-&Count();
运行程序看到如下效果
&&&&&&&&&&&
&&&&&&&&&&& 16.为了给CPU更多的时间,我们不需要程序运行很快,我们如何限制渲染速度,打开AppGame.h 加入下面代码, 再运行可以看到 Fps已经是30了
protected:
&&& // 保存主程序句柄
&&& HINSTANCE m_hI
&&& // 保存主窗口句柄
&&& HWND m_hW
&&& // 最后一次渲染的时间
&&& DWORD m_dwRenderLastT
&&&&& 17.在主渲染函数中加入
// 主渲染函数
void CAppGame::Render()
&&& if( timeGetTime() - m_dwRenderLastTime & 33 )
&&& m_dwRenderLastTime = timeGetTime();
第五章& 精灵动画
&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&& 在游戏中跑来跑去的小人,小狗,Tank 等叫做精灵,每个精灵都会有一张图画,如果会做动作的会有几张图画交替显示,从而看起来像是在跑。如图 28x28大小的一个图块是精灵动画的一张图片,后面的那个是第二张,我们把这每一张图片叫做帧, 我们说Tank的上方向行走是2帧动画。
在我们的项目中,我们定义帧的方法是 记录一个图快的位置和大小
如图 X,Y,W,H 来表示一个帧。
1.在TANK项目中加入一个目录Animation,并增加6个文件 Frame.h
Frame.cpp Animation.h Animation.cpp SpriteManager.h SpriteManager.cpp
&&&&&&&&&&& 2.在Frame.h 和Frame.cpp 增加帧类代码
#ifndef __Frame_H__
#define __Frame_H__
#include "GDISurface.h"
// 动画帧类
class CFrame
&&& // 在ImageC上的位置和大小
&&& int m_iX;
&&& int m_iY;
&&& int m_iW;
&&& int m_iH;
&&& // 渲染到表面
&&& void Render( CGDISurface *pSurface, int iX, int iY, CGDISurface::BltMode iMode );
#endif // __Frame_H__
Frame.cpp :
#include "Frame.h"
#include "ShareData.h"
// 渲染到表面
void CFrame::Render( CGDISurface *pSurface, int iX, int iY, CGDISurface::BltMode iMode )
&&& theImageC-&Blt( pSurface, iX, iY, m_iX, m_iY, m_iW, m_iH, iMode );
3.打开Animation.h 输入下面代码
#ifndef __Animation_H__
#define __Animation_H__
#include "Frame.h"
#include &vector&
class CAnimation
&&& CAnimation();
&&& virtual ~CAnimation();
& &&// 加入帧
&&& void Push( CFrame& f );
&&& // 获得总帧数
&&& int GetMaxFrame();
&&& // 获得某帧数据
&&& CFrame *GetFrame( int iFrame );
protected:
&&& // 帧数据
&&& std::vector&CFrame& m_vectorF
#endif // __Animation_H__
4.&&&&&&&&&&& 打开Animation.cpp 输入下面代码
#include "Animation.h"
CAnimation::CAnimation()
&&& m_vectorFrame.clear();
CAnimation::~CAnimation()
&&& m_vectorFrame.clear();
void CAnimation::Push( CFrame& f )
&&& m_vectorFrame.push_back( f );
// 获得总帧数
int CAnimation::GetMaxFrame()
&&& return (int)m_vectorFrame.size();
// 获得某帧数据
CFrame *CAnimation::GetFrame( int iFrame )
&&& if( iFrame & 0 && iFrame &= (int)m_vectorFrame.size() )
&&&&&&& return NULL;
&&& return &m_vectorFrame[iFrame];
5.&&&&&&&&&&& 打开SpriteManager.h 输入下面代码
#ifndef __SpriteManager_H__
#define __SpriteManager_H__
#include "Animation.h"
class CSpriteManager
&&& CSpriteManager();
&&& virtual ~CSpriteManager();
&&& // 创建动画数据集
&&& bool Create();
&&& // 释放动画数据集
&&& void Release();
&&& // 获得动画数据
&&& CAnimation *GetAnimation( int index );
&&& // 获得动画总数
&&& int GetAnimationNumber();
protected:
&&& // 存储动画数据
&&& std::vector& CAnimation & m_vectorA
#endif // __SpriteManager_H__
6.打开SpriteManager.cpp 输入下面代码
#include "SpriteManager.h"
CSpriteManager::CSpriteManager()
CSpriteManager::~CSpriteManager()
// 创建动画数据集
bool CSpriteManager::Create()
// 释放动画数据集
void CSpriteManager::Release()
&&& m_vectorAnimation.clear();
// 获得动画数据
CAnimation *CSpriteManager::GetAnimation( int index )
&&& if( index & 0 || index &= (int)m_vectorAnimation.size() )
&&&&&&& return NULL;
&&& // 返回index所指的动画
&&& return &m_vectorAnimation[index];
// 获得动画总数
int CSpriteManager::GetAnimationNumber()
&&& return (int)m_vectorAnimation.size();
&&&&&&&&&&& 7.在CSpriteManager::Create()里加入第一个动画,动画也可能只有1帧。下面是加入前两个帧给0号动画。同样的方法,可以在此函数里加入所有动画。
// 创建动画数据集
bool CSpriteManager::Create()
&&& CAnimation *pA
&&& // 第一个动画
&&& pAni = new CAnimation();
&&& // 第一帧 (0,0,28,28)
&&& f.m_iX = 0;
&&& f.m_iY = 0;
&&& f.m_iW = 28;
&&& f.m_iH = 28;
&&& pAni-&Push( f );
&&& // 第二帧 (28,0,28,28)
&&& f.m_iX = 28;
&&& f.m_iY = 0;
&&& f.m_iW = 28;
&&& f.m_iH = 28;
&&& pAni-&Push( f );
&&& // Ani ID = 0 两帧动画加入动画库
&&& m_vectorAnimation.push_back( *pAni );
& &&delete pA
&&&&&&&&&&& 8.在ShareData.h ShareData.cpp 里分别加入下面代码
ShareData.h:
#ifndef __ShareData_H__
#define __ShareData_H__
#include "GDIGraphicsDevice.h"
#include "GDISurface.h"
#include "GDITextRender.h"
#include "Fps.h"
#include "SpriteManager.h"
extern CGDIGraphicsDevice *theGraphicsD
extern CGDISurface *theImageC;
extern CGDITextRender *theTextR
extern CFps *theRenderF
extern CSpriteManager *theSpriteM
#endif // __ShareData_H__
ShareData.cpp:
#include "ShareData.h"
CGDIGraphicsDevice *theGraphicsDevice = NULL;
CGDISurface *theImageC = NULL;
CGDITextRender *theTextRender = NULL;
CFps *theRenderFps = NULL;
CSpriteManager *theSpriteManager = NULL;
&&&& 9.在AppGame.cpp里加入下面初始化和释放动画管理器代码
&&& theTextRender = new CGDITextRender();
&&& if( !theTextRender-&Create( &FontInfo ) )
&&&&&&& OutputDebugString( "Create theTextRender Failed/n" );
&&& // 创建渲染刷新率统计器
&&& theRenderFps = new CFps();
&&& // 创建动画管理器
&&& theSpriteManager = new CSpriteManager();
&&& if( !theSpriteManager-&Create() )
&&&&&&& OutputDebugString( "Create Sprite Manager Failed/n" );
// 结束程序
void CAppGame::Terminal()
&&& // 释放动画管理器
&&& theSpriteManager-&Release();
&&& delete theSpriteM
&&& theSpriteManager = NULL;
&&&&&&&&&&& 10.在 CAppGame::Render()里作如下修改,显示一个动画的一帧。
&&& // 清除主表面
&&& pScreen-&Clear( RGB( 127,127, 127 ) );
&&& // 显示位图
&&& //theImageC-&Blt( pScreen, 30, 30, 0, 0, WindowWidth(), WindowHeight(), CGDISurface::BLT_ALPHATEST );
&&& // 显示一个动画的一帧
&&& CAnimation *pAni = theSpriteManager-&GetAnimation( 0 );
&&& CFrame *pF = pAni-&GetFrame( 0 );
&&& pF-&Render( pScreen, 100, 100, CGDISurface::BLT_ALPHATEST );
&&& // 显示文字
&&& theTextRender-&TextOut( pScreen, 0, 0, FSTR( "FPS = %2d", theRenderFps-&GetFps() ), RGB( 255, 255, 255 ) );
&&&&&&&&&&& 大家可以看到显示效果是,一个Tank显示在屏幕上。
10.接下来的任务就是就是把这些动画编排好,以便以后使用。根据下面的图我们可以看出,这组图是很有规律,这是每一个TANK的4个方向上的动画,我写了一个循环按照规则创建动画在CSpriteManager.cpp Create()函数里加入初始化代码
// 创建动画数据集
bool CSpriteManager::Create()
&&& CAnimation *pA
&&& // 所有TANK图片都是28x28
&&& f.m_iW = 28;
&&& f.m_iH = 28;
&&& // 两组动画,上面是玩家TANK,下面是地方TANK。
&&& for( int k=0; k&2; k++ )
&&&&&&& // 每一大组内有8种TANK的动画
&&&&&&& for( int l=0; l&8; l++ )
&&&&&&& &&&&// 每种Tank有4个方向上的动画
&&&&&&&&&&& for( int j=0; j&4; j++ )
&&&&&&&&&&& {
&&&&&&&&&&&&&&& pAni = new CAnimation();
&&&&&&&&&&&&&&& // 每个方向上的动画有2帧
&&&&&&&&&&&&&&& for( int i=0; i&2; i++ )
&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&& f.m_iX = l*28*2 + i*28;
&&&&& &&&&&&&&&&&&&&f.m_iY = k*28*4 + j*28;
&&&&&&&&&&&&&&&&&&& pAni-&Push( f );
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& m_vectorAnimation.push_back( *pAni );
&&&&&&&&&&&&&&& delete pA
&&&&&&&&&&& }
&&& // 动画定位公式是: 动画ID = 坦克型号 * 4 + 方向
11.在CAppGame::Render()里加入并修改代码,运行程序可以看到TANK行走动画,每2秒钟随机变化一个TANK
&&& // 显示位图
&&& //theImageC-&Blt( pScreen, 30, 30, 0, 0, WindowWidth(), WindowHeight(), CGDISurface::BLT_ALPHATEST );
&&& // 当前帧
&&& static int iCurFrame = 0;
&&& // 动画计时开始时间
&&& static DWORD dwAniStartTime = timeGetTime();
&&& // 当前动画ID
&&& static int iCurAni = 0;
&&& // 最后一次改变动画的时间
&&& static DWORD dwAniChangeLastTime = timeGetTime();
&&& if( timeGetTime() - dwAniChangeLastTime & 2000 )
&&&&&&& iCurAni = rand()%64;
&&&&&&& dwAniChangeLastTime = timeGetTime();
&&& if( timeGetTime() - dwAniStartTime & 33 )
&&&&&&& iCurFrame++;
&&&&&&& if( iCurFrame &= 2 )
&&&&&&&&&&& iCurFrame = 0;
&&&&&&& dwAniStartTime = timeGetTime();
&&& // 显示一个动画的一帧
&&& CAnimation *pAni = theSpriteManager-&GetAnimation( iCurAni );
&&& CFrame *pF = pAni-&GetFrame( iCurFrame );
&&& pF-&Render( pScreen, 100, 100, CGDISurface::BLT_ALPHATEST );
第六章 &场景
一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!
二、互相尊重,对自己的言论和行为负责。
本文标题:
本页链接:}

我要回帖

更多关于 ps快速入门 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信