




已阅读5页,还剩69页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
VC+win32API游戏开发,1,VC+win32API游戏开发,1.Windows编程2.Windows应用程序的组成与编程3.游戏实现原理与WindowGDI绘图4.游戏实例的剖析,2,1.Windows编程,1.1WindowsAPI编程基础1.2窗口1.3事件驱动1.4句柄1.5消息1.6Windows应用程序的常用消息,3,1.1WindowsAPI编程基础,Windows编程的方法主要有两种方法:传统编写法:利用API函数。交互式方法:利用MFC类库。为使程序员编写具有Windows风格的应用程序,Windows提供了一个应用程序编程接口(ApplicationProgrammingInterface,简称API),它是Windows系统与Windows应用程序间的标准程序接口。上千个API函数包含了各种窗口类和系统资源。API可以为应用程序提供windows系统特殊函数及数据结构。windows应用程序可以利用大量API函数调用系统功能。,4,MFC,MFC,MicrosoftFoundationClassLibrary,微软基础类库,约有200个类。MFC封装了大部分API函数,并提供了一个应用程序框架,简化了和标准了windows程序设计。但WindowsAPI编程方法始终是windows编程的基础。,5,1.2窗口,编写一个Windows应用程序首先应创建一个或多个窗口,而后应用程序的运行过程即是窗口内部、窗口与窗口之间、窗口与系统之间进行数据处理与数据交换的过程。,6,1.3事件驱动,Windows程序设计是针对事件或消息的,它的执行顺序取决于事件发生的顺序。在Windows环境下,应用程序启动后,系统等待用户在图形用户界面内的输入选择,如鼠标按键、键盘按键、窗口被创建、关闭、改变大小、移动等,对系统来说,这都是事件,都会产生相应的windows消息。事件驱动编程方法对于编写交互式程序很有用处,它避免了死板的操作模式。,7,1.4句柄,句柄,顾名思义,指的是一个windows对象的把柄。Windows中的句柄都是32位的指针变量,用来指向某个windows对象所占据的内存区。句柄的使用,极大地方便了Windows管理其内存中的各种windows对象。,8,常用句柄类型及其说明,9,1.5消息,消息是描述事件发生的信息。Windows应用程序通过消息进行信息交换。在Windows中,消息用结构体MSG表示,其结构如下:TypedefstructtagMSGHWNDhwnd;/窗口句柄UNITmessage;/消息号。WPARAMwParam;/用于提供消息的附加消息。LPARAMlParam;/用于提供消息的附加消息。DWORDtime;/指定消息送至队列的时间POINTpt;/指定消息发送时屏幕光标的位置MSG;,10,VC+中存在几种系统定义的消息分类,不同的前缀符号经常用于识别消息的分类,如下表所示:,11,1.6Windows应用程序的常用消息,1.鼠标消息,主要有:WM_LBUTTONDOWN:产生单击鼠标左键的消息。WM_LBUTTONUP:放开鼠标左键时产生的消息。2.键盘消息,主要有:WM_KEYDOWN:按下一个系统键时产生的消息。WM_KEYUP:放开一个系统键时产生的消息。3.窗口消息,主要有:WM_CREATE:窗口创建时,由CreateWindows函数发出的消息。WM_CLOSE:关闭窗口时产生的消息。WM_QUIT:退出应用程序时,由PostQuitMessage函数发出消息。,12,2.Windows应用程序的组成与编程,2.1典型的Windows程序结构2.2入口函数WinMain()2.3窗口函数WinProc()2.4windows应用程序的常用数据类型2.5API编程实例,13,2.1典型的Windows程序结构,Windows应用程序的主体由以下两个函数完成:WinMain()函数负责建立窗口和建立消息循环。WinProc()函数负责消息的处理。,14,2.1典型的Windows程序结构,15,2.2入口函数WinMain(),WinMain()函数类似C语言中的Main函数,是Win32应用程序入口函数。WinMain()函数主要完成创建主窗口,并产生和处理消息循环。,16,WinMain()函数,因为windows是多任务系统,所以同一应用程序的多个窗口可能会同时存在。windows系统对每个窗口的执行称为一个实例,用一个实例句柄来唯一标识。WinMain()函数与DOS程序的main()函数起同样的作用,有一点不同的是,WinMain()函数必须带有四个参数,它们是系统传递给它的。WinMain()函数的原型如下:intPASCALWinMain(HINSTANCEhInstance,/当前实例句柄HINSTANCEhPrevInstance,/前一个实例句柄LPSTRlpCmdLine,/命令行字符intnCmdShow)/窗口显示方式,17,WinMain()函数,第一个参数hInstance,是标识该应用程序当前实例的句柄。第二个参数是hPrevInstance,它是用来标识该应用程序的前一个实例的句柄。第三个参数是lpCmdLine,是指向应用程序命令行参数字符串的指针。最后一个参数是nCmdShow,是一个用来指定窗口显示方式的整数。这个整数值可以是SW_SHOW、SW_HIDE、SW_SHOWMAXIMIZED、SW_SHOWMINIMIZED等。,18,WinMain()函数主要由2部分组成:窗口初始化消息循环,19,窗口初始化包括以下主要步骤:,定义窗口类:通过给窗口类数据结构WINDCLASS赋值,设置窗口类的各种属性。如窗口边框、窗口标题栏文字、窗口大小和位置、鼠标、背景色等。注册窗口类:Win系统本身提供部分预定义的窗口类,程序员也可以自定义窗口类。窗口类必须先注册后使用。窗口类的注册由函数RegisterClass()实现。创建窗口实例:创建窗口类的实例由CreateWindows()函数实现。窗口显示:窗口类的显示是由ShowWindows()函数和UpdateWindows()函数实现的。ShowWindows()函数:应用程序通过调用ShowWindows()函数在屏幕上显示窗口。UpdateWindows()函数:显示窗口后,应用程序调用UpdateWindow更新并绘制用户区,并发出WM_PAINT消息。,20,消息循环,Windows为当前执行的每个Windows程序维护一个消息队列。在发生输入事件之后,Windows将事件转换为一个消息并将消息放入程序的消息队列中。程序通过执行一块称之为消息循环的程序代码从消息队列中取出消息。以下是WinMain()函数中消息循环的代码:/消息循环以调用GetMessage()开始,它从消息队列中取出/一个消息while(GetMessage(,21,WinMain()函数的大致结构,intPASCALWinMain()/定义窗口类:WNDCLASSwndclass;wndclass.style=CS_HREDRAW|CS_VREDRAW;十个字段wndclass.lpszClassName=”Lei”;/注册窗口类:RegisterClass(,22,2.3窗口函数WndProc(),窗口函数WndProc()就是Windows应用程序的消息处理程序。窗口函数WndProc()定义了应用程序对接收到的不同消息的响应,包含了对各种可能接收到的消息的处理过程。WndProc函数由一个或多个switch语句组成。每一条case语句对应一种消息,当应用程序接收到一个消息时,相应的case语句被激活并执行相应的响应程序模块。窗口消息处理程序不予处理的所有消息被传给名为DefWindowProc的Windows函数进行默认处理。,23,消息处理函数WndProc的大致结构,LRESULTCALLBACKWndProc(HWNDhMainwnd,UINTmessage,WPARAMwParam,LPARAMlParam)/窗口函数的定义switch(message)caseWM_KEYDOWN:/击键消息;break;case:;break;caseWM_DESTROY:/关闭应用程序窗口时发出的消息PostQuitMessage(0);/发出WM_QUIT消息,结束应用程序return0;default:break;/调用缺省消息处理过程returnDefWindowProc(hMainwnd,message,wParam,lParam);,24,2.4windows应用程序的常用数据类型,25,所有的Windows应用程序中,都有一个程序初始化的过程。下面以一个实现最简单功能的程序WinApiDemo为例,说明Windows程序的基本框架。操作步骤如下:(1)打开VisualC+6.0。选择File菜单的New,在出现的对话框中,选择Projects栏目(新建工程),并点取其下的Win32Application项,表示使用Win32环境创建应用程序。(2)在Locatin(路径)中填入工程的路径,然后在ProjectName(项目名称)中填入“WinApiDemo”,其它按照缺省设置,单击OK按钮。(3)选择File菜单的New,在出现的对话框中,选择Files栏目(新建文件),并点取其下的C+SourceFile项,表示新建一个C+源文件。在右边的File栏中输入“WinApiDemo”,最后确定让Addtoproject检查框打上勾,单击OK按钮。(4)在“WinApiDemo.cpp”文件中输入以下程序代码。,2.5API编程实例,26,WinApiDemo.cpp源代码(1),#include/头文件LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);/窗口函数声明,这一函数将处理发往应用程序窗口的各种消息charszClassName=windowclass;/窗口结构体的名称charszAppTitle=API建立窗口实例;/窗口的标题INTPASCALWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpszCmdParam,INTnCmdShow)/WinMain()函数的定义HWNDhMainWnd;/窗口句柄MSGmsg;/消息结构体WNDCLASSwinclass;/窗口结构体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(/注册窗口,27,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(,28,WinApiDemo.cpp源代码(3),LRESULTCALLBACKWndProc(HWNDhMainwnd,UINTmessage,WPARAMwParam,LPARAMlParam)/窗口函数的定义switch(message)caseWM_KEYDOWN:/击键消息MessageBox(hMainwnd,键按下了!,Keyboard,MB_OK);break;caseWM_RBUTTONDOWN:/鼠标消息MessageBox(hMainwnd,鼠标右键按下了!,Mouse,MB_OK);break;caseWM_LBUTTONDOWN:/鼠标消息MessageBox(hMainwnd,鼠标左键按下了!,Mouse,MB_OK);break;caseWM_DESTROY:/关闭应用程序窗口时发出的消息PostQuitMessage(0);/发出WM_QUIT消息,结束应用程序return0;default:break;/调用缺省消息处理过程returnDefWindowProc(hMainwnd,message,wParam,lParam);,29,WinApiDemo.cpp源代码(4),caseWM_RBUTTONDOWN:MessageBox(GetFocus(),messageright,API建立窗口实例,MB_OK|MB_ICONINFORMATION);break;caseWM_LBUTTONDOWN:MessageBox(GetFocus(),messageleft,API建立窗口实例,MB_OK|MB_ICONINFORMATION);break;caseWM_DESTROY:/关闭应用程序窗口时发出的消息PostQuitMessage(0);/发出WM_QUIT消息,结束应用程序return0;default:break;returnDefWindowProc(hMainwnd,message,wParam,lParam);/其它没有处理的消息交给Windows做默认处理,30,WinApiDemo的运行画面,31,3.游戏实现原理与WindowGDI绘图,3.1游戏实现的基本原理3.2WindowGDI基本概念3.3利用GDI实现游戏中的绘图,32,3.1游戏实现的基本原理,33,3.2WindowGDI基本概念,GDI,GraphicsDeviceInterface,即图形设备接口,是WindowsAPI的一个重要组成部分。GDI是Windows图形显示程序与实际物理设备之间的桥梁,GDI使得用户无需关心具体设备的细节,而只需在一个虚拟的环境(即逻辑设备)中进行操作。GDI用一套通用的图形对象来向屏幕,內存甚至是打印机绘图。,34,GDI函数大致可分类为:设备上下文函数:如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。,35,设备上下文,在GDI编程中,几乎所有的操作都围绕设备上下文(DC)展开。设备上下文,DeviceContext,简称DC,是Windows使用的一种结构,所有GDI操作前都需取得特定设备的上下文。设备上下文的句柄是HDC。HDC是一个你可以向其绘图的句柄;它可以代表整个屏幕,一个窗口的客戶区域,一个存在內存中的位图,或是一个打印机。例如,如果你想在一个窗口上绘图,首先你要用GetDC()来获取代表这个窗口的HDC,然后你就可以用任何以HDC为参数的GDI函数来绘图了。,36,位图,位图可以用LoadBitmap()来完成大多数的基本操作,比如简单地装入一个位图资源。GDI不能直接用位图对象来绘图,因为绘图操作已经被设备上下文抽象了,只能通过设备上下文来绘制位图。利用位图绘图的大体思路是:把位图对象装入设备上下文,通过设备上下文把位图显示在屏幕上。,37,3.3利用GDI实现游戏中的绘图,游戏中的绘图主要通过是绘制位图来实现的。在游戏中,因为角色位图的位置是不断变化的,所以设备上下文中的合成位图的内容也是不断变化的。为了实现游戏画面的刷新,通常是利用缓存设备上下文来保存下一帧的合成位图对象。下一帧的合成位图对象是根据角色位图的实时位置和状态重新渲染后的结果。,38,39,40,下面举例给出了利用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上显示。,41,GetDC()函数,函数功能:该函数检索一指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄,以后可以在GDI函数中使用该句柄来在设备上下文环境中绘图。函数原型:HDCGetDC(HWNDhWnd);参数:hWnd:设备上下文环境被检索的窗口的句柄,如果该值为NULL,GetDC则检索整个屏幕的设备上下文环境。返回值:如果成功,返回指定窗口客户区的设备上下文环境;如果失败,返回值为Null。,42,CreateCompatibleDC()函数,函数功能:该函数创建一个与指定设备兼容的内存设备上下文环境(DC)。函数原型:HDCCreateCompatibleDC(HDChdc);参数:hdc:现有设备上下文环境的句柄,如果该句柄为NULL,该函数创建一个与应用程序的当前显示器兼容的内存设备上下文环境。返回值:如果成功,则返回内存设备上下文环境的句柄;如果失败,则返回值为NULL。,43,CreateCompatibleBitmap()函数,函数功能:该函数创建与指定的设备环境相关的设备兼容的位图。函数原型:HBITMAPCreateCompatibleBitmap(HDChdc,intnWidth,intnHeight);参数:hdc:设备环境句柄。nWidth:指定位图的宽度,单位为像素。nHeight:指定位图的高度,单位为像素。返回值:如果函数执行成功,那么返回值是位图的位图句柄;如果函数执行失败,那么返回值为NULL。,44,LoadBitmap()函数,函数功能:该函数从模块的可执行文件中加载指定的位图资源。函数原型:HBITMAPLoadBitmap(HINSTANCEhInstance,LPCTSTRlpBitmapName);参数:hlnstance:指向模块实例的句柄。lpBitmapName:指向字符串指针。该字符串包含了要加载的位图资源名称。返回值:如果函数执行成功,则返回值是指向指定位图的位图句柄。如果函数执行失败,那么返回值是NULL。,45,SelectObject()函数,函数功能:该函数选择一对象到指定的设备上下文环境中。函数原型:HGDIOBJSelectObject(HDChdc,HGDIOBJhgdiobj);参数:hdc:设备上下文环境的句柄。hgdiobj:被选择的对象的句柄,这些对象包括位图、画刷、字体、笔、区域等。返回值:如果选择对象不是区域并且函数执行成功,那么返回值是对象的句柄。,46,BitBlt()函数,函数功能:该函数对指定的源设备环境区域中的像素进行位块转换,并传送到目标设备环境。函数原型:BOOLBitBlt(HDChdcDest,intnXDest,intnYDest,intnWidth,intnHeight,HDChdcSrc,intnXSrc,intnYSrc,DWORDdwRop);参数:hdcDest:指向目标设备环境的句柄。nXDest:指定目标矩形区域左上角的X轴逻辑坐标。nYDest:指定目标矩形区域左上角的Y轴逻辑坐标。nWidth:指定源和目标矩形区域的逻辑宽度。nHeight:指定源和目标矩形区域的逻辑高度。hdcSrc:指向源设备环境的句柄。nXSrc:指定源矩形区域左上角的X轴逻辑坐标。nYSrc:指定源矩形区域左上角的Y轴逻辑坐标。dwRop:指定光栅操作代码。这些代码将定义源矩形区域的颜色数据,如何与目标矩形区域的颜色数据运算以完成最后的颜色。,47,常见的光栅操作代码(dwRop),SRCCOPY:将源矩形区域直接拷贝到目标矩形区域。SRCAND:通过使用AND(与)操作符来将源和目标矩形区域内的颜色合并。SRCPAINT:通过使用布尔型的OR(或)操作符将源和目标矩形区域的颜色合并。WHITENESS:使用与物理调色板中索引1有关的颜色填充目标矩形区域。(对于缺省物理调色板来说,这个颜色就是白色)。BLACKNESS:表示使用与物理调色板的索引0相关的色彩来填充目标矩形区域,(对缺省的物理调色板而言,该颜色为黑色)。DSTINVERT:表示使目标矩形区域颜色取反。MERGECOPY:表示使用布尔型的AND(与)操作符将源矩形区域的颜色与特定模式组合一起。MERGEPAINT:通过使用布尔型的OR(或)操作符将反向的源矩形区域的颜色与目标矩形区域的颜色合并。NOTSRCCOPY:将源矩形区域颜色取反,于拷贝到目标矩形区域。NOTSRCERASE:使用布尔类型的OR(或)操作符组合源和目标矩形区域的颜色值,然后将合成的颜色取反。,48,计算机中的GRB颜色,在计算机中,使用的是数字图像处理,每一种颜色都是由RGB表示的,RGB是指红(RED)、绿(GREEN)、蓝(BLUE)三原色。RGB颜色值是红绿蓝3种颜色的强度,每个原色的GRB颜色值的取值范围为0(#00)255(#FF)。RGB16进制颜色值即是红绿蓝三原色各自16进制颜色值的组合。如(255,255,255)的16进制颜色值为#FFFFFF。举例:白色是三原色值均为最大时混合成的的颜色,所以颜色表示为(255,255,255),16进制就用#FFFFFF表示。黑色是三原色值均为最小时混合成的的颜色,所以颜色表示为(0,0,0),16进制就用#000000表示。,49,50,在数字图像处理中可以实现OR、AND等逻辑运算。运算规律如下:任何颜色同白色(#FFFFFF)进行OR运算结果都为白色,进行AND运算结果都是该颜色本身。任何颜色同黑色(#000000)进行OR运算结果都为该颜色本身,进行AND运算结果都是黑色。例如,可以进行对图1所示的位图进行去“背景色”的处理:首先将“图2”位图同目标地颜色进行“或”(OR)运算,得到的结果是:“图2”白色处为白色,其他处为目标地颜色。再将“图1”位图同目标地颜色进行“与”(AND)运算,得到的结果是:“图1”位图水果处为原颜色,而其他处为目标地颜色,从而达到了精确“去背”的效果。,图1,图2,51,假设,图1所示的尺寸为160px80px,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,52,实现位图绘图的核心代码,HDCwindowDC=NULL;/windows屏幕设备HDCbufferDC=NULL;/缓冲设备环境HDCpicDC=NULL;/位图内存设备HBITMAPpicBMP=NULL;/位图句柄HBITMAPbufferBMP=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);/将窗口的初始画面位图选入缓冲DCSelectObject(picDC,picBMP);/将角色位图选入选入角色位图DCBitBlt(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);,53,4.游戏实例剖析,分析:贪吃蛇游戏是一个深受人们喜爱的游戏,一条蛇在密闭的围墙内沿当前方向移动,在围墙内不断随机出现水果和毒果。玩家通过按键盘上的四个光标键控制蛇头向上下左右四个方向移动,如果蛇头吃到水果,蛇的身体长一节,分数加100分。如果蛇头撞到墙壁或蛇头触碰到其身体或吃到毒果,游戏结束。,54,55,程序的要点:,用一个小矩形块表示蛇的一节身体,身体每长一节,增加一个矩形块。移动时必须从蛇头开始,所以蛇不能向相反方向移动。如不按任何键,蛇自行在当前方向上前移。当游戏者按了有效的方向键后,蛇头朝着指定的方向移动,一步移动一节身体,所以当按了有效的方向键后,先确定蛇头的位置,然后蛇身体随着蛇头移动,图形的实现是从蛇头的新位置开始画出蛇。根据以上分析,设计了两个类:CTable类、CSnack类。,56,主要基本数据结构及常量的定义(1),/节点图像显示运动状态(方向)enumBitmapStateM_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;/节点运动状态(方向)enumMoveStateS_NONE,S_UP,S_DOWN,S_LEFT,S_RIGHT;/坐标位置结构structSPointintx;inty;#defineTB_STATE_OK0/正常#defineTB_STATE_FOOD1/食物#defineTB_STATE_BLOCK2/障碍毒果#defineTB_STATE_SBLOCK3/障碍墙,57,主要基本数据结构及常量的定义(2),/游戏状态定义#defineGAME_STATE_WAIT0/游戏等待状态#defineGAME_STATE_RUN1/游戏运行状态#defineGAME_STATE_END2/游戏结束状态/界面相关物件尺寸定义#defineWALL_WIDTH80/外墙从左部到游戏区的宽度#defineWALL_HEIGHT80/外墙从顶部到游戏区的高度#defineBMP_SCORE_BOARD_WIDTH256/分数位图板的宽度#defineBMP_SCORE_BOARD_HEIGHT55/分数位图板的高度#defineBMP_WALL_WIDTH16/墙位图的宽度#defineBMP_WALL_HEIGHT16/墙位图的高度,58,classCSnakestructSnake_Struct/定义蛇体状态MoveStatehead;/头部MoveState*body;/身体MoveStatetail;/尾部;private:intm_length;/蛇的长度Snake_Structm_newSnake;/蛇的新态的所有节点运动状态Snake_Structm_oldSnake;/蛇的原态的所有节点运动状态BitmapState*m_pStateArray;/蛇的所有节点显示位图的状态SPoint*m_pPos;/蛇体坐标private:BitmapStateGetRightState(MoveStateoldDirect,MoveStatenewDirect);/根据新旧两个身体的运动趋势情况,返回当前应当显示的身体状态public:voidMove(void);voidChangeDirect(MoveStated);/改变方向,条件:非对立方向voidAddBody(intn=1);/蛇的身体增长voidSetHeadPos(intx,inty);/设置蛇头的坐标BitmapState*GetStateArray(void);/取蛇的状态标识数组SPoint*GetPos(void);/取蛇的位置数组boolIsHeadTouchBody(intx,inty);/检测蛇头是否触碰到其身体intGetLength(void);/取蛇身的长度voidInitial(void);/初始化用作游戏结束后重新开始public:CSnake(intx_pos=0,inty_pos=0,intlen=1);CSnake();,59,classCTableprivate:intm_width;/桌子的宽度intm_height;/桌子的高度intm_foodNumber;/水果的数目intm_blockNumber;/障碍物(毒果)的数目CSnakem_snake;/桌子上的蛇int*m_board;/桌子面板,二维数组public:CTable();CTable();voidInitialTable(intw,inth);/初始化桌子面板boolAddBlock(intx,inty);/在某个位置放置毒果boolAddFood(intx,inty);/在某个位置放置水果boolClearFood(intx,inty);/清除某个位置的果实CSnake*GetSnake(void);/获取蛇对象int*GetBoard(void);/取桌子对象intGetData(intx,inty);/取桌子某个位置数据voidSnakeMove(void);/蛇的移动boolChangeSnakeDirect(MoveStated);/改变蛇的方向;,60,主程序(main.cpp)中的全局变量,CTabletable;/创建一个桌子inttableBlockWidth=0;/桌子的格子的宽度inttableBlockHeight=0;/桌子的格子的高度intiScores=0;/游戏的得分UINTuGameState=GAME_STATE_WAIT;/当前游戏状态HDCwindowDC=NULL;/windows屏幕设备HDCbufferDC=NULL;/缓冲设备环境HDCpicDC=NULL;/snake图像内存设备HDCendDC=NULL;/游戏终结图像内存设备HDCscoreDC=NULL;/分数板内存设备HWNDhAppWnd=NULL;/本application窗口句柄HBITMAPpicBMP=NULL;/snake图像位图句柄HBITMAPbufferBMP=NULL;/缓冲位图句柄HBITMAPendBMP=NULL;/游戏终结图像内存句柄HBITMAPhbmpWall=NULL;/墙位图句柄HBITMAPhbmpScore=NULL;/分数板位图句柄HBRUSHhbrushWall=NULL;/墙画刷UINTuSnakeMoveTimer;/蛇移动的定时器标识UINTuFoodAddTimer;/水果产生的定时器标识/框架的位置数据定义RECTg_ClientRect;RECTg_GameValueRect;intg_iClientWidth;intg_iClientHeight;,61,intWINAPIWinMain(HINSTANCEhCurrentInst,HINSTANCEhPrevInstance,PSTRlpszCmdLine,intnCmdShow)WNDCLASSwndClass;HWNDhWnd;MSGmsg;UINTwidth,height;/定义窗口wndClass.style=CS_HREDRAW|CS_VREDRAW;wndClass.lpszClassName=Snake_CLASS;/注册窗口RegisterClass(,WinMain()方法-(1),62,WinMain()方法-(2),/获取窗体大小GetClientRect(hAppWnd,63,WinMain()方法-(3),/声明位图与设备环境的关联SelectObject(bufferDC,bufferBMP);SelectObject(picDC,picBMP);SelectObject(endDC,endBMP);SelectObject(scoreDC,hbmpScore);/建立画刷与其名相对应的图像的关联,/以备用刷子将墙刷出来,用PatBlt()实现hbrushWall=CreatePatternBrush(hbmpWall);StartGame();while(GetMessage(,64,WndProc()方法-(1),LRESULTCALLBACKWndProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)switch(message)caseWM_TIMER:OnTimer(UINT)wParam);break;caseWM_KEYDOWN:switch(wParam)caseVK_ESCAPE:exit(0);break;caseVK_UP:table.ChangeSnakeDirect(S_UP);break;caseVK_DOWN:table.ChangeSnakeDirect(S_DOWN);break;caseVK_LEFT:table.ChangeSnakeDirect(S_LEFT);break;caseVK_RIGHT:table.ChangeSnakeDirect(S_RIGHT);break;caseVK_SPACE:if(uGameState=GAME_STATE_END)StartGame();break;return0;,65,WndProc()方法-(2),caseWM_SETCURSOR:SetCursor(NULL);return0;caseWM_DESTROY:ReleaseDC(hWnd,picDC);ReleaseDC(hWnd,bufferDC);ReleaseDC(hWnd,windowDC);PostQuitMessage(0);return0;returnDefWindowProc(hWnd,message,wParam,lParam);,66,voidStartGame()iScores=0;/桌面的初始化table.InitialTable(tableBlockWidth,tableBlockHeight);table.GetSnake()-ChangeDirect(S_RIGHT);table.GetSnake()-SetHeadPos(tableBlockWidth/2,tableBlockHeight/2);/预先随机产生几个食物srand(unsigned)time(NULL);for(intiFoodNum=0;iFoodNumIsHeadTouchBody(table.GetSnake()-GetPos()0.x,table.GetSnake()-GetPos()0.y)EndGame();/根据蛇头所在的区域作出相应的处理switch(table.GetData(table.GetSnake()-GetPos()0.x,table.GetSnake()-GetPos()0.y)caseTB_STATE_FOOD:table.ClearFood(table.GetSnake()-GetPos()0.x,table.GetSnake()-GetPos()0.y);table.AddBlock(rand()%tableBlockWidth,(rand()%tableBlockHeight);table.GetSnake()-AddBody();+iScores;break;caseTB_STATE_BLOCK:caseTB_STATE_SBLOCK:EndGame();/检测是否碰到障碍物,结束游戏break;DrawGame();/显示elseif(uTIMER_ID=uFoodAddTimer)/定时加食物table.AddFood(rand()%tableBlockWidth,(rand()%tableBlockHeight);,68,voidDrawGame(void)ShellDraw(bufferDC);/绘制外壳区域到缓冲GameAreaDraw(bufferDC);/绘制游戏区域到缓冲/将整个画面从缓冲DCbufferDC拷贝到屏幕BitBlt(windowDC,0,0,g_iClientWidth,g_iClientHeight,bufferDC,0,0,SRCCOPY);voidShellDraw(HDChdc)/分数提示显示文字charszText30=Score:;charszNum20;intiNowScore=iScores*100;itoa(iNowScore,szNum,10);strcat(szText,szNum);RECTrt,rect;GetClientRect(hAppWnd,69,GameAreaDraw()方法-(1),voidGameAreaDraw(HDChdc)inti,j;intx,y,x_pos,y_pos;BitmapStatestate;/绘制水果与毒果for(i=0;iGetPos()0.y;x_pos=x*20+WALL_WIDTH;y_pos=y*20+WALL_HEIGHT;state=table.GetSnake()-GetStateArray()0;switch(state)caseM_UP_UP:BitBlt(hdc,x_pos,y_pos,20,20,picDC,80,20,SRCPAINT);BitBlt(hdc,x_pos,y_pos,20,20,picDC,0,20,SRCAND);break;caseM_DOWN_DOWN:BitBlt(hdc,x_pos,y_pos,20,20,picDC,140,20,SRCPAINT);BitBlt(hdc,x_pos,y_pos,20,20,picDC,60,20,SRCAND);break;caseM_LEFT_LEFT:BitBlt(hdc,x_pos,y_pos,20,20,picDC,100,20,SRCPAINT);BitBlt(hdc,x_pos,y_pos,20,2
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 篷布帐篷的快速搭建与拆卸技巧考核试卷
- 空间信息技术与地理信息系统考核试卷
- 空气净化器产品创新趋势与市场需求分析预测考核试卷
- 玩具行业互联网+营销模式考核试卷
- 组织领导力发展与绩效管理体系构建实践考核试卷
- 直播平台与健身教练合作直播协议
- 粤港澳大湾区跨境股权投资人工智能合作协议
- 商业街区店铺经营权审查及管理服务合同
- 跨界娱乐直播合作项目主播签约协议
- 物流运输数据安全备份及恢复服务补充协议
- 分期还款协议书模板示例
- 幼升小公有住宅租赁合同(2篇)
- 彩票大数据预测分析
- (完整)老旧小区改造施工组织设计
- 2024-2030年中国科技服务行业发展前景及投资策略分析研究报告
- 《城市轨道交通》课件
- 建筑工程材料取样送检一览表
- 婚姻家庭继承法期末考试复习题及参考答案
- 2024年四川省成都市中考数学试卷(含解析)
- 项目全周期现金流管理培训课件
- 小学群众满意度调查测评表
评论
0/150
提交评论