nullVC++ win32 API 游戏开发VC++ win32 API 游戏开发VC++ win32 API 游戏开发VC++ win32 API 游戏开发1.Windows 编程
2.Windows应用程序的组成与编程
3. 游戏实现原理与Window GDI绘图
4.游戏实例的剖析1.Windows编程1.Windows编程1.1 Windows API编程基础
1.2 窗口
1.3 事件驱动
1.4 句柄
1.5 消息
1.6 Windows应用程序的常用消息1.1 Windows API编程基础1.1 Windows API编程基础Windows编程的方法主要有两种方法:
传统编写法:利用API函数。
交互式方法:利用MFC类库。
为使程序员编写具有Windows风格的应用程序,Windows提供了一个应用程序编程接口(Application Programming Interface,简称API),它是Windows系统与Windows应用程序间的标准程序接口。
上千个API函数包含了各种窗口类和系统资源。
API可以为应用程序提供windows系统特殊函数及数据结构。
windows应用程序可以利用大量API函数调用系统功能。MFCMFCMFC, Microsoft Foundation Class Library,微软基础类库,约有200个类。
MFC封装了大部分API函数,并提供了一个应用程序框架,简化了和标准了windows程序设计。
但Windows API编程方法始终是windows编程的基础。
1.2 窗口1.2 窗口编写一个Windows应用程序首先应创建一个或多个窗口,而后应用程序的运行过程即是窗口内部、窗口与窗口之间、窗口与系统之间进行数据处理与数据交换的过程。1.3 事件驱动1.3 事件驱动Windows程序设计是针对事件或消息的,它的执行顺序取决于事件发生的顺序。
在Windows环境下,应用程序启动后,系统等待用户在图形用户界面内的输入选择,如鼠标按键、键盘按键、窗口被创建、关闭、改变大小、移动等,对系统来说,这都是事件,都会产生相应的windows消息。
事件驱动编程方法对于编写交互式程序很有用处,它避免了死板的操作模式。1.4 句柄1.4 句柄句柄,顾名思义,指的是一个windows对象的把柄。
Windows中的句柄都是32位的指针变量,用来指向某个windows对象所占据的内存区。
句柄的使用,极大地方便了Windows管理其内存中的各种windows对象。常用句柄类型及其说明常用句柄类型及其说明1.5 消息1.5 消息消息是描述事件发生的信息。
Windows应用程序通过消息进行信息交换。
在Windows中,消息用结构体MSG表示,其结构如下:
Typedef struct tagMSG
{ HWND hwnd; //窗口句柄
UNIT message; //消息号。
WPARAM wParam;//用于提供消息的附加消息。
LPARAM lParam;//用于提供消息的附加消息。
DWORD time;//指定消息送至队列的时间
POINT pt; //指定消息发送时屏幕光标的位置
}MSG; VC++中存在几种系统定义的消息分类,不同的前缀符号经常用于识别消息的分类,如下表所示: VC++中存在几种系统定义的消息分类,不同的前缀符号经常用于识别消息的分类,如下表所示:1.6 Windows应用程序的常用消息1.6 Windows应用程序的常用消息1.鼠标消息,主要有:
WM_LBUTTONDOWN:产生单击鼠标左键的消息。
WM_LBUTTONUP:放开鼠标左键时产生的消息。
……
2.键盘消息,主要有:
WM_KEYDOWN:按下一个系统键时产生的消息。
WM_KEYUP:放开一个系统键时产生的消息。
……
3.窗口消息,主要有:
WM_CREATE:窗口创建时,由CreateWindows函数发出的消息。
WM_CLOSE:关闭窗口时产生的消息。
WM_QUIT:退出应用程序时,由PostQuitMessage函数发出消息。
……2.Windows应用程序的组成与编程2.Windows应用程序的组成与编程2.1 典型的Windows程序结构
2.2 入口函数WinMain()
2.3 窗口函数WinProc()
2.4 windows应用程序的常用数据类型
2.5 API编程实例2.1 典型的Windows程序结构2.1 典型的Windows程序结构Windows应用程序的主体由以下两个函数完成:
WinMain()函数负责建立窗口和建立消息循环。
WinProc()函数负责消息的处理。2.1 典型的Windows程序结构2.1 典型的Windows程序结构2.2 入口函数WinMain()2.2 入口函数WinMain()WinMain()函数类似C语言中的Main函数,是Win32应用程序入口函数。
WinMain()函数主要完成创建主窗口,并产生和处理消息循环。
WinMain()函数 WinMain()函数 因为windows是多任务系统,所以同一应用程序的多个窗口可能会同时存在。
windows系统对每个窗口的执行称为一个实例,用一个实例句柄来唯一标识。
WinMain()函数与DOS程序的main()函数起同样的作用,有一点不同的是,WinMain()函数必须带有四个参数,它们是系统传递给它的。
WinMain()函数的原型如下:
int PASCAL WinMain( HINSTANCE hInstance, //当前实例句柄
HINSTANCE hPrevInstance, //前一个实例句柄
LPSTR lpCmdLine, //命令行字符
int nCmdShow) //窗口显示方式WinMain()函数WinMain()函数第一个参数hInstance,是标识该应用程序当前实例的句柄。
第二个参数是hPrevInstance,它是用来标识该应用程序的前一个实例的句柄。
第三个参数是lpCmdLine,是指向应用程序命令行参数字符串的指针。
最后一个参数是nCmdShow,是一个用来指定窗口显示方式的整数。这个整数值可以是SW_SHOW、SW_HIDE、SW_SHOWMAXIMIZED、SW_SHOWMINIMIZED等。nullWinMain()函数主要由2部分组成:
窗口初始化
消息循环
窗口初始化包括以下主要步骤:窗口初始化包括以下主要步骤:定义窗口类: 通过给窗口类数据结构WINDCLASS赋值,设置窗口类的各种属性。如窗口边框、窗口标题栏文字、窗口大小和位置、鼠标、背景色等。
注册窗口类: Win系统本身提供部分预定义的窗口类,程序员也可以自定义窗口类。窗口类必须先注册后使用。窗口类的注册由函数RegisterClass()实现。
创建窗口实例: 创建窗口类的实例由CreateWindows()函数实现。
窗口显示: 窗口类的显示是由ShowWindows()函数和UpdateWindows()函数实现的。
ShowWindows()函数:应用程序通过调用ShowWindows()函数在屏幕上显示窗口。
UpdateWindows()函数:显示窗口后,应用程序调用UpdateWindow更新并绘制用户区,并发出WM_PAINT消息。消息循环 消息循环 Windows为当前执行的每个Windows程序维护一个[消息队列]。
在发生输入事件之后,Windows将事件转换为一个[消息]并将消息放入程序的[消息队列]中。
程序通过执行一块称之为[消息循环]的程序代码从消息队列中取出消息。
以下是WinMain()函数中消息循环的代码:
//消息循环以调用GetMessage()开始,它从消息队列中取出//一个消息
while (GetMessage (&msg, NULL, 0, 0))
{
//将消息msg结构传给Windows,进行一些键盘转换。
TranslateMessage (&msg) ;
//将该消息发送给窗口消息处理程序进行处理。
DispatchMessage (&msg) ;
}WinMain()函数的大致结构 WinMain()函数的大致结构 int PASCAL WinMain(…… )
{
//①定义窗口类:
WNDCLASS wndclass;
wndclass.style=CS_HREDRAW|CS_VREDRAW;
…… 十个字段
wndclass.lpszClassName=”Lei”;
//②注册窗口类:
RegisterClass(&wndclass);
//③创建窗口:
HWND hwnd;
hwnd=CreateWindow();
//④显示及更新窗口:
ShowWindow();
UpdateWindow();
//⑤消息循环:
MSG msg;
While(GetMessage(&msg,NULL,0,0))
{ TranlateMessage(&msg);
DispatchMessage(&msg)
}
return msg.wParam;
}2.3 窗口函数WndProc()2.3 窗口函数WndProc()窗口函数WndProc()就是Windows应用程序的消息处理程序。
窗口函数WndProc()定义了应用程序对接收到的不同消息的响应,包含了对各种可能接收到的消息的处理过程。
WndProc函数由一个或多个switch语句组成。每一条case语句对应一种消息,当应用程序接收到一个消息时,相应的case语句被激活并执行相应的响应程序模块。
窗口消息处理程序不予处理的所有消息被传给名为DefWindowProc的Windows函数进行默认处理。消息处理函数WndProc的大致结构 消息处理函数WndProc的大致结构 LRESULT CALLBACK WndProc(HWND hMainwnd, UINT message, WPARAM wParam, LPARAM lParam) //窗口函数的定义
{ switch( message )
{ case WM_KEYDOWN://击键消息
{ …… ;
break;
}
case ……:
{ ……;
break;
}
……
case WM_DESTROY://关闭应用程序窗口时发出的消息
{ PostQuitMessage(0);//发出WM_QUIT消息,结束应用程序
return 0;
}
default : break;
}
//调用缺省消息处理过程
return DefWindowProc(hMainwnd, message, wParam, lParam);
}2.4 windows应用程序的常用数据类型2.4 windows应用程序的常用数据类型2.5 API编程实例所有的Windows应用程序中,都有一个程序初始化的过程。
下面以一个实现最简单功能的程序WinApiDemo为例,说明Windows程序的基本框架。操作步骤如下:
(1)打开Visual C++ 6.0。 选择File菜单的New,在出现的对话框中,选择Projects栏目(新建工程),并点取其下的Win32 Application项,表示使用Win32环境创建应用程序。
(2)在Locatin(路径)中填入工程的路径,然后在Project Name(项目名称)中填入“WinApiDemo”,其它按照缺省设置,单击OK按钮。
(3)选择File菜单的New,在出现的对话框中,选择Files栏目(新建文件),并点取其下的C++ Source File项,表示新建一个C++源文件。在右边的File栏中输入“WinApiDemo”,最后确定让Add to project检查框打上勾,单击OK按钮。
(4)在“WinApiDemo.cpp”文件中输入以下程序代码。2.5 API编程实例 WinApiDemo.cpp源代码(1) WinApiDemo.cpp源代码(1) #include
//头文件
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
//窗口函数声明,这一函数将处理发往应用程序窗口的各种消息
char szClassName[]="windowclass";//窗口结构体的名称
char szA
ppt
关于艾滋病ppt课件精益管理ppt下载地图下载ppt可编辑假如ppt教学课件下载triz基础知识ppt
itle[]="API建立窗口实例";//窗口的标题
INT PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam , INT nCmdShow)
//WinMain()函数的定义
{ HWND hMainWnd;//窗口句柄
MSG msg;//消息结构体
WNDCLASS winclass;//窗口结构体
if(!hPrevInstance)
{ winclass.style=CS_HREDRAW|CS_VREDRAW;//窗口风格
winclass.lpfnWndProc=WndProc;
winclass.cbClsExtra=0;//附加参数
winclass.cbWndExtra=0;//附加参数
winclass.hInstance=hInstance;//当前应用程序实例句柄
winclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);//窗口图标
winclass.hCursor=LoadCursor(NULL,IDC_ARROW);//窗口光标
winclass.hbrBackground=(HBRUSH)GetStockObject(LTGRAY_BRUSH);
//窗口背景色为浅灰色
winclass.lpszMenuName=NULL;//窗口菜单
winclass.lpszClassName=szClassName; //给窗口结构体命名,
//CreateWindow()函数将根据窗口结构体的名称来建立窗口
RegisterClass(&winclass);//注册窗口
}WinApiDemo.cpp源代码(2)WinApiDemo.cpp源代码(2) //下面用CreateWindow()函数来建立窗口,并返回所建立窗口的句柄
hMainWnd=CreateWindow(
szClassName,//窗口结构体的名称
szAppTitle,//窗口的标题
WS_OVERLAPPEDWINDOW,//窗口风格为可重叠窗口
//下面四个参数代表窗口左上角x,y坐标和窗口的宽度与高度,都使
//用缺省值
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
//下面参数分别为父窗口句柄、窗口菜单句柄、应用程序实例句柄
//和附加参数
NULL,NULL,hInstance,NULL);
ShowWindow(hMainWnd,SW_SHOWNORMAL);
//显示最大化窗口
UpdateWindow(hMainWnd);//更新窗口
//下面用While()循环来建立消息循环
while(GetMessage(&msg,NULL,0,0))//获取消息,填充msg结构体
{ TranslateMessage(&msg);//翻译键盘消息
DispatchMessage(&msg);//向窗口函数发送消息,让窗口函数处理
}
return msg.wParam;
}WinApiDemo.cpp源代码(3)WinApiDemo.cpp源代码(3)LRESULT CALLBACK WndProc(HWND hMainwnd, UINT message, WPARAM wParam, LPARAM lParam) //窗口函数的定义
{ switch( message )
{ case WM_KEYDOWN://击键消息
{ MessageBox(hMainwnd,"键按下了!","Keyboard",MB_OK);
break;
}
case WM_RBUTTONDOWN://鼠标消息
{ MessageBox(hMainwnd,"鼠标右键按下了!","Mouse",MB_OK);
break;
}
case WM_LBUTTONDOWN://鼠标消息
{ MessageBox(hMainwnd,"鼠标左键按下了!","Mouse",MB_OK);
break;
}
case WM_DESTROY://关闭应用程序窗口时发出的消息
{ PostQuitMessage(0);//发出WM_QUIT消息,结束应用程序
return 0;
}
default : break;
}
//调用缺省消息处理过程
return DefWindowProc(hMainwnd, message, wParam, lParam);
}WinApiDemo.cpp源代码(4)WinApiDemo.cpp源代码(4) case WM_RBUTTONDOWN:
{ MessageBox(GetFocus(),messageright,"API建立窗口实例",MB_OK|MB_ICONINFORMATION);
break;
}
case WM_LBUTTONDOWN:
{ MessageBox(GetFocus(),messageleft,"API建立窗口实例",MB_OK|MB_ICONINFORMATION);
break;
}
case WM_DESTROY://关闭应用程序窗口时发出的消息
{ PostQuitMessage(0);
//发出WM_QUIT消息,结束应用程序
return 0;
}
default : break;
}
return DefWindowProc(hMainwnd,message,wParam,lParam);
//其它没有处理的消息交给Windows做默认处理
}WinApiDemo的运行画面WinApiDemo的运行画面3.游戏实现原理与Window GDI绘图3.游戏实现原理与Window GDI绘图3.1 游戏实现的基本原理
3.2 Window GDI基本概念
3.3 利用GDI实现游戏中的绘图3.1 游戏实现的基本原理3.1 游戏实现的基本原理3.2 Window GDI基本概念3.2 Window GDI基本概念GDI,Graphics Device Interface,即图形设备接口,是Windows API的一个重要组成部分。
GDI是Windows图形显示程序与实际物理设备之间的桥梁,GDI使得用户无需关心具体设备的细节,而只需在一 个虚拟的环境(即逻辑设备)中进行操作。
GDI用一套通用的图形对象来向屏幕,內存甚至是打印机绘图。nullGDI函数大致可分类为:
设备上下文函数:如GetDC、CreateDC、DeleteDC。
画线函数:如LineTo、Polyline、Arc。
填充画图函数:如Ellipse、FillRect、Pie。
画图属性函数:如 SetBkColor、SetBkMode、SetTextColor。
文本、字体函数:如TextOut、GetFontData。
位图函数:如 SetPixel、BitBlt、StretchBlt。
坐标函数:如DPtoLP、LPtoDP、ScreenToClient、 ClientToScreen。
映射函数:如SetMapMode、SetWindowExtEx、SetViewportExtEx。
元文件函数:如PlayMetaFile、SetWinMetaFileBits。
区域函数:如FillRgn、FrameRgn、InvertRgn。
路径函 数:如BeginPath、EndPath、StrokeAndFillPath。
裁剪函数:如SelectClipRgn、 SelectClipPath。设备上下文设备上下文在GDI编程中,几乎所有的操作都围绕设备上下文(DC)展开。
设备上下文,Device Context,简称DC,是Windows 使用的一种结构,所有GDI操作前都需取得特定设备的上下文。
设备上下文的句柄是HDC。
HDC是一个你可以向其绘图的句柄;它可以代表整个屏幕,一个窗口的客戶区域,一个存在內存中的位图,或是一个打印机。
例如,如果你想在一个窗口上绘图,首先你要用GetDC()来获取代表这个窗口的HDC,然后你就可以用任何以HDC为参数的GDI函数来绘图了。位图位图位图可以用LoadBitmap()来完成大多数的基本操作,比如简单地装入一个位图资源。
GDI不能直接用位图对象来绘图,因为绘图操作已经被设备上下文抽象了,只能通过设备上下文来绘制位图。
利用位图绘图的大体思路是:把位图对象装入设备上下文,通过设备上下文把位图显示在屏幕上。3.3 利用GDI实现游戏中的绘图3.3 利用GDI实现游戏中的绘图游戏中的绘图主要通过是绘制位图来实现的。
在游戏中,因为角色位图的位置是不断变化的,所以设备上下文中的合成位图的内容也是不断变化的。
为了实现游戏画面的刷新,通常是利用缓存设备上下文来保存下一帧的合成位图对象。
下一帧的合成位图对象是根据角色位图的实时位置和状态重新渲染后的结果。nullnullnull下面举例给出了利用GDI实现位图绘图的主要步骤:
定义windows屏幕设备句柄变量windowDC;
定义窗口缓冲设备句柄变量bufferDC;
定义一个位图内存设备句柄变量picDC;
定义一个位图句柄变量picBMP;
定义一个缓冲位图句柄变量bufferBMP;
调用GetDC()获取当前整个屏幕设备的句柄值,赋给windowDC;
调用CreateCompatibleDC()创建与windowDC兼容的内存设备,并将其句柄值赋给位图内存设备变量picDC。
调用CreateCompatibleDC()创建与windowDC兼容的内存设备,并其句柄值赋给窗口缓冲设备变量bufferDC。
调用CreateCompatibleBitmap()创建与windowDC兼容的位图对象,并将该位图的句柄值赋给bufferBMP。
调用LoadBitmap()加载指定位图资源,并获取给该位图资源的句柄值,赋给picBMP。
调用SelectObject()将缓冲位图句柄bufferBMP和窗口缓冲设备句柄bufferDC关联。
调用SelectObject()将位图句柄picBMP和位图内存设备picDC关联。
两次调用特定运算的BitBlt()函数来对位图内存设备picDC中的位图进行“去背”处理后,把结果保存在窗口缓冲设备bufferDC中。
调用BitBlt()函数将窗口缓冲设备中的全部图像内容拷贝到屏幕设备windowDC上显示。GetDC()函数GetDC()函数函数功能:该函数检索一指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄,以后可以在GDI函数中使用该句柄来在设备上下文环境中绘图。
函数原型:HDC GetDC(HWND hWnd);
参数:
hWnd:设备上下文环境被检索的窗口的句柄,如果该值为NULL,GetDC则检索整个屏幕的设备上下文环境。
返回值:如果成功,返回指定窗口客户区的设备上下文环境;如果失败,返回值为Null。CreateCompatibleDC()函数CreateCompatibleDC()函数函数功能:该函数创建一个与指定设备兼容的内存设备上下文环境(DC)。
函数原型:HDC CreateCompatibleDC(HDC hdc);
参数:
hdc:现有设备上下文环境的句柄,如果该句柄为NULL,该函数创建一个与应用程序的当前显示器兼容的内存设备上下文环境。
返回值:如果成功,则返回内存设备上下文环境的句柄;如果失败,则返回值为NULL。CreateCompatibleBitmap()函数CreateCompatibleBitmap()函数函数功能:该函数创建与指定的设备环境相关的设备兼容的位图。
函数原型:HBITMAP CreateCompatibleBitmap(HDC hdc,int nWidth,int nHeight);
参数:
hdc: 设备环境句柄。
nWidth:指定位图的宽度,单位为像素。
nHeight:指定位图的高度,单位为像素。
返回值:如果函数执行成功,那么返回值是位图的位图句柄;如果函数执行失败,那么返回值为NULL。
LoadBitmap()函数LoadBitmap()函数函数功能:该函数从模块的可执行文件中加载指定的位图资源。
函数原型:HBITMAP LoadBitmap(HINSTANCE hInstance, LPCTSTR lpBitmapName);
参数:
hlnstance:指向模块实例的句柄。
lpBitmapName:指向字符串指针。该字符串包含了要加载的位图资源名称。
返回值:如果函数执行成功,则返回值是指向指定位图的位图句柄。如果函数执行失败,那么返回值是NULL。SelectObject()函数SelectObject()函数函数功能:该函数选择一对象到指定的设备上下文环境中。
函数原型:HGDIOBJ SelectObject(HDC hdc, HGDIOBJ hgdiobj);
参数:
hdc:设备上下文环境的句柄。
hgdiobj:被选择的对象的句柄,这些对象包括位图、画刷、字体、笔、区域等。
返回值:如果选择对象不是区域并且函数执行成功,那么返回值是对象的句柄。BitBlt()函数 BitBlt()函数 函数功能:该函数对指定的源设备环境区域中的像素进行位块转换,并传送到目标设备环境。
函数原型:BOOL BitBlt(HDC hdcDest,int nXDest,int nYDest,int nWidth,int nHeight,HDC hdcSrc,int nXSrc,int nYSrc,DWORD dwRop);
参数:
hdcDest:指向目标设备环境的句柄。
nXDest:指定目标矩形区域左上角的X轴逻辑坐标。
nYDest:指定目标矩形区域左上角的Y轴逻辑坐标。
nWidth:指定源和目标矩形区域的逻辑宽度。
nHeight:指定源和目标矩形区域的逻辑高度。
hdcSrc:指向源设备环境的句柄。
nXSrc:指定源矩形区域左上角的X轴逻辑坐标。
nYSrc:指定源矩形区域左上角的Y轴逻辑坐标。
dwRop:指定光栅操作代码。这些代码将定义源矩形区域的颜色数据,如何与目标矩形区域的颜色数据运算以完成最后的颜色。常见的光栅操作代码( dwRop )常见的光栅操作代码( dwRop )SRCCOPY:将源矩形区域直接拷贝到目标矩形区域。
SRCAND:通过使用AND(与)操作符来将源和目标矩形区域内的颜色合并。
SRCPAINT:通过使用布尔型的OR(或)操作符将源和目标矩形区域的颜色合并。
WHITENESS:使用与物理调色板中索引1有关的颜色填充目标矩形区域。(对于缺省物理调色板来说,这个颜色就是白色)。
BLACKNESS:表示使用与物理调色板的索引0相关的色彩来填充目标矩形区域,(对缺省的物理调色板而言,该颜色为黑色)。
DSTINVERT:表示使目标矩形区域颜色取反。
MERGECOPY:表示使用布尔型的AND(与)操作符将源矩形区域的颜色与特定模式组合一起。
MERGEPAINT:通过使用布尔型的OR(或)操作符将反向的源矩形区域的颜色与目标矩形区域的颜色合并。
NOTSRCCOPY:将源矩形区域颜色取反,于拷贝到目标矩形区域。
NOTSRCERASE:使用布尔类型的OR(或)操作符组合源和目标矩形区域的颜色值,然后将合成的颜色取反。计算机中的GRB颜色计算机中的GRB颜色在计算机中,使用的是数字图像处理,每一种颜色都是由RGB表示的,RGB是指红(RED)、绿(GREEN)、蓝(BLUE)三原色。
RGB颜色值是红绿蓝3种颜色的强度,每个原色的GRB颜色值的取值范围为0(#00)~255(#FF)。
RGB 16进制颜色值即是红绿蓝三原色各自16进制颜色值的组合。如(255,255,255)的16进制颜色值为#FFFFFF。
举例:
白色是三原色值均为最大时混合成的的颜色,所以颜色表示为(255,255,255),16进制就用#FFFFFF表示。
黑色是三原色值均为最小时混合成的的颜色,所以颜色表示为(0,0,0),16进制就用#000000表示。nullnull在数字图像处理中可以实现OR、AND等逻辑运算。运算规律如下:
任何颜色同白色(#FFFFFF)进行OR运算结果都为白色,进行AND运算结果都是该颜色本身。
任何颜色同黑色(#000000)进行OR运算结果都为该颜色本身,进行AND运算结果都是黑色。
例如,可以进行对图1所示的位图进行去“背景色”的处理:
首先将“图2”位图同目标地颜色进行“或”(OR)运算,得到的结果是:“图2”白色处为白色,其他处为目标地颜色。
再将“图1”位图同目标地颜色进行“与”(AND)运算,得到的结果是:“图1”位图水果处为原颜色,而其他处为目标地颜色,从而达到了精确“去背”的效果。图1图2null 假设,图1所示的尺寸为160px×80px,hdc为内存句柄,picDC为该位图的内存位图句柄。则:
以下两条语句会达到的效果:在屏幕(x_pos,y_pos)上显示“蛇头朝上”位图”:
BitBlt(hdc,x_pos,y_pos,20,20,picDC,80,20,SRCPAINT);//或运算
BitBlt(hdc,x_pos,y_pos,20,20,picDC,0,20,SRCAND);//与运算
以下两条语句会会达到的效果:在屏幕(x_pos,y_pos)上显示“蛇头朝下”位图:
BitBlt(hdc,x_pos,y_pos,20,20,picDC,140,20,SRCPAINT);
BitBlt(hdc,x_pos,y_pos,20,20,picDC,60,20,SRCAND);图1 实现位图绘图的核心代码实现位图绘图的核心代码……
HDC windowDC = NULL; //windows屏幕设备
HDC bufferDC = NULL; //缓冲设备环境
HDC picDC=NULL; //位图内存设备
HBITMAP picBMP = NULL; //位图句柄
HBITMAP bufferBMP = NULL; //缓冲位图句柄
windowDC=GetDC(NULL);
bufferDC=CreateCompatibleDC(windowDC);
picDC=CreateCompatibleDC(windowDC);
//g_iClientWidth,g_iClientHeight分别是窗口的宽和高。
bufferBMP=CreateCompatibleBitmap(windowDC,g_iClientWidth,g_iClientHeight);
picBMP=(HBITMAP)LoadImage(NULL,"snake.bmp",IMAGE_BITMAP,160,80,LR_LOADFROMFILE);
SelectObject(bufferDC,bufferBMP);//将窗口的初始画面位图选入缓冲DC
SelectObject(picDC,picBMP);//将角色位图选入选入角色位图DC
……
BitBlt(bufferDC,x_pos,y_pos,20,20,picDC,80,20,SRCPAINT);//或运算
BitBlt(bufferDC,x_pos,y_pos,20,20,picDC,0,20,SRCAND);//与运算
//将整个画面从缓冲DC拷贝出屏幕
BitBlt(windowDC,0,0,g_iClientWidth,g_iClientHeight,bufferDC,0,0,SRCCOPY);4.游戏实例剖析4.游戏实例剖析分析:贪吃蛇游戏是一个深受人们喜爱的游戏,一条蛇在密闭的围墙内沿当前方向移动,在围墙内不断随机出现水果和毒果。
玩家通过按键盘上的四个光标键控制蛇头向上下左右四个方向移动,
如果蛇头吃到水果,蛇的身体长一节,分数加100分。
如果蛇头撞到墙壁或蛇头触碰到其身体或吃到毒果,游戏结束。null程序的要点:程序的要点:用一个小矩形块表示蛇的一节身体,身体每长一节,增加一个矩形块。
移动时必须从蛇头开始,所以蛇不能向相反方向移动。
如不按任何键,蛇自行在当前方向上前移。
当游戏者按了有效的方向键后,蛇头朝着指定的方向移动,一步移动一节身体,所以当按了有效的方向键后,先确定蛇头的位置,然后蛇身体随着蛇头移动,图形的实现是从蛇头的新位置开始画出蛇。
根据以上分析,设计了两个类:CTable类、CSnack类。主要基本数据结构及常量的定义(1)主要基本数据结构及常量的定义(1)//节点图像显示运动状态(方向)
enum BitmapState{ M_NONE,M_UP_UP,M_DOWN_DOWN,
M_LEFT_LEFT,M_RIGHT_RIGHT,M_UP_LEFT,M_UP_RIGHT,
M_LEFT_UP,M_LEFT_DOWN,M_RIGHT_UP,M_RIGHT_DOWN,
M_DOWN_RIGHT,M_DOWN_LEFT };
//节点运动状态(方向)
enum MoveState{S_NONE,S_UP,S_DOWN,S_LEFT,S_RIGHT};
//坐标位置结构
struct SPoint
{ int x;
int y;
};
#define TB_STATE_OK 0 //正常
#define TB_STATE_FOOD 1 //食物
#define TB_STATE_BLOCK 2 //障碍-毒果
#define TB_STATE_SBLOCK 3 //障碍-墙主要基本数据结构及常量的定义(2)主要基本数据结构及常量的定义(2)//游戏状态定义
#define GAME_STATE_WAIT 0 //游戏等待状态
#define GAME_STATE_RUN 1 //游戏运行状态
#define GAME_STATE_END 2 //游戏结束状态
//界面相关物件尺寸定义
#define WALL_WIDTH 80 //外墙从左部到游戏区的宽度
#define WALL_HEIGHT 80 //外墙从顶部到游戏区的高度
#define BMP_SCORE_BOARD_WIDTH 256 //分数位图板的宽度
#define BMP_SCORE_BOARD_HEIGHT 55 //分数位图板的高度
#define BMP_WALL_WIDTH 16 //墙位图的宽度
#define BMP_WALL_HEIGHT 16 //墙位图的高度nullclass CSnake
{ struct Snake_Struct//定义蛇体状态
{ MoveState head; //头部
MoveState *body; //身体
MoveState tail; //尾部
};
private: int m_length; //蛇的长度
Snake_Struct m_newSnake; //蛇的新态的所有节点运动状态
Snake_Struct m_oldSnake; //蛇的原态的所有节点运动状态
BitmapState *m_pStateArray; //蛇的所有节点显示位图的状态
SPoint *m_pPos; //蛇体坐标
private: BitmapState GetRightState(MoveState oldDirect,MoveState newDirect);//根据新旧两个身体的运动趋势情况,返回当前应当显示的身体状态
public: void Move(void);
void ChangeDirect(MoveState d); //改变方向,条件:非对立方向
void AddBody(int n=1);//蛇的身体增长
void SetHeadPos(int x,int y);//设置蛇头的坐标
BitmapState* GetStateArray(void);//取蛇的状态标识数组
SPoint* GetPos(void);//取蛇的位置数组
bool IsHeadTouchBody(int x,int y);//检测蛇头是否触碰到其身体
int GetLength( void );//取蛇身的长度
void Initial( void ); //初始化 用作游戏结束后重新开始
public: CSnake(int x_pos=0,int y_pos=0,int len=1);
~CSnake();
};nullclass CTable{
private:
int m_width; //桌子的宽度
int m_height; //桌子的高度
int m_foodNumber; //水果的数目
int m_blockNumber; //障碍物(毒果)的数目
CSnake m_snake; //桌子上的蛇
int **m_board; //桌子面板,二维数组
public:
CTable();
~CTable();
void InitialTable(int w,int h); //初始化桌子面板
bool AddBlock(int x,int y); // 在某个位置放置毒果
bool AddFood(int x,int y); // 在某个位置放置水果
bool ClearFood(int x,int y);//清除某个位置的果实
CSnake* GetSnake(void);// 获取蛇对象
int** GetBoard(void); // 取桌子对象
int GetData(int x,int y);// 取桌子某个位置数据
void SnakeMove(void);// 蛇的移动
bool ChangeSnakeDirect(MoveState d);// 改变蛇的方向
};主程序(main.cpp)中的全局变量主程序(main.cpp)中的全局变量CTable table; //创建一个桌子
int tableBlockWidth = 0; //桌子的格子的宽度
int tableBlockHeight = 0; //桌子的格子的高度
int iScores = 0; //游戏的得分
UINT uGameState = GAME_STATE_WAIT; //当前游戏状态
HDC windowDC = NULL; //windows屏幕设备
HDC bufferDC = NULL; //缓冲设备环境
HDC picDC = NULL; //snake图像内存设备
HDC endDC = NULL; //游戏终结图像内存设备
HDC scoreDC = NULL; //分数板内存设备
HWND hAppWnd = NULL; //本application窗口句柄
HBITMAP picBMP = NULL; //snake图像位图句柄
HBITMAP bufferBMP = NULL; //缓冲位图句柄
HBITMAP endBMP = NULL; //游戏终结图像内存句柄
HBITMAP hbmpWall = NULL; //墙位图句柄
HBITMAP hbmpScore = NULL; //分数板位图句柄
HBRUSH hbrushWall = NULL; //墙画刷
UINT uSnakeMoveTimer; //蛇移动的定时器标识
UINT uFoodAddTimer; //水果产生的定时器标识
//框架的位置数据定义
RECT g_ClientRect;
RECT g_GameValueRect;
int g_iClientWidth;
int g_iClientHeight;WinMain()方法 ---(1)int WINAPI WinMain(HINSTANCE hCurrentInst,HINSTANCE hPrevInstance, PSTR lpszCmdLine,int nCmdShow)
{ WNDCLASS wndClass;
HWND hWnd;
MSG msg;
UINT width,height;
//定义窗口
wndClass.style=CS_HREDRAW | CS_VREDRAW;
……
wndClass.lpszClassName="Snake_CLASS";
//注册窗口
RegisterClass(&wndClass);
//取整个屏幕的尺寸
width=GetSystemMetrics(SM_CXSCREEN);
height= GetSystemMetrics(SM_CYSCREEN);
//创建窗口
hWnd=CreateWindow( "Snake_CLASS","skyblue snake",
WS_POPUP,0,0,width,height,NULL,NULL,hCurrentInst,NULL);
hAppWnd = hWnd;
//显示窗口
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);WinMain()方法 ---(1)WinMain()方法 ---(2)WinMain()方法 ---(2)//获取窗体大小
GetClientRect(hAppWnd, &g_ClientRect);
g_iClientWidth = g_ClientRect.right-g_ClientRect.left;
g_iClientHeight = g_ClientRect.bottom-g_ClientRect.top;
//将游戏区域分成纵,横均为20块的小方块,并计算每块区域的大小
tableBlockWidth = (g_iClientWidth-2*WALL_WIDTH)/20;
tableBlockHeight = (g_iClientHeight-2*WALL_HEIGHT)/20;
windowDC=GetDC(NULL); //获取当前主窗口设备与windowDC关联
//创建与windowDC兼容的内存设备环境
bufferDC=CreateCompatibleDC(windowDC);
picDC=CreateCompatibleDC(windowDC);
endDC=CreateCompatibleDC(windowDC);
scoreDC=CreateCompatibleDC(windowDC);
//位图的初始化或载入位图
bufferBMP=CreateCompatibleBitmap(windowDC,g_iClientWidth,g_iClientHeight);
picBMP=(HBITMAP)LoadImage(NULL,"snake.bmp",IMAGE_BITMAP,160,80,LR_LOADFROMFILE);
hbmpWall=(HBITMAP)LoadImage(NULL,"brick.bmp",IMAGE_BITMAP,16,16,LR_LOADFROMFILE);
endBMP = (HBITMAP)LoadImage(NULL,"end.bmp",IMAGE_BITMAP,369,300,LR_LOADFROMFILE);
hbmpScore=(HBITMAP)LoadImage(NULL,"scoreboard.bmp",IMAGE_BITMAP,265,55,LR_LOADFROMFILE);WinMain()方法 ---(3)WinMain()方法 ---(3) //声明位图与设备环境的关联
SelectObject(bufferDC,bufferBMP);
SelectObject(picDC,picBMP);
SelectObject(endDC,endBMP);
SelectObject(scoreDC,hbmpScore);
//建立画刷与其名相对应的图像的关联,
//以备用刷子将墙刷出来,用PatBlt()实现
hbrushWall = CreatePatternBrush(hbmpWall);
StartGame();
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}WndProc()方法--(1)WndProc()方法--(1)LRESULT CALLBACK WndProc(HWND hWnd,UINT message, WPARAM wParam,LPARAM lParam)
{ switch(message)
{ case WM_TIMER :
OnTimer((UINT)wParam);