C++课程设计报告——贪吃蛇和迷宫的设计及实现

本文详细介绍了使用C++进行贪吃蛇和迷宫游戏的设计与实现,涵盖了游戏规则、需求分析、功能模块设计、算法说明、游戏运行效果以及总结。在贪吃蛇游戏部分,涉及游戏控制、资源管理、交互元素等多个模块;迷宫部分则讨论了迷宫数据结构、生成与寻路算法。整个项目展示了C++在游戏开发中的应用,强调了软件工程中的模块化设计和错误处理的重要性。

 

qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmrtyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmrtyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmrtyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmrtyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmrtyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmrtyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmrtyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm

 

 

C++课程设计报告

——贪吃蛇和迷宫的设计及实现

 

 

 

 

 

 

 

 

 

 

 

 

学院:信息科学与工程学院

专业:电气信息类        

班级:1230班            

姓名:保密              

学号:保密        

2013/7/7 Sunday

 

 

 


 

目录

卷一:贪吃蛇的设计及实现

 

一、         系统描述... 1

游戏规则:... 1

游戏需求:... 1

概要设计:... 1

环境要求:... 2

二、         功能模块结构... 2

模块:... 2

类视图(详情请参见附件):... 3

三、         主要模块的算法说明:... 3

游戏控制模块:... 3

资源管理模块:... 4

交互元素模块:... 4

游戏规则模块:... 4

绘图模块:5

音效模块:... 5

错误处理模块:... 5

四、         游戏运行效果:... 5

五、         总结:... 8

六、         参考文献:... 9

七、         附录:... 9

程序清单(详情请查看工程文件):... 9

卷二:迷宫的设计及实现

一、         系统描述... 51

规则:... 51

需求分析:... 51

二、         功能模块结构... 51

显示模块:... 52

迷宫数据结构:... 52

迷宫生成思路:... 52

迷宫寻路思路:... 53

三、         迷宫运行效果:... 54

四、         总结:... 55

五、         参考文献:... 56

六、         附录:... 56

 

 


卷一:贪吃蛇的设计及实现

     

一、    系统描述

游戏规则

贪吃蛇游戏采用传统的游戏规则,实现蛇的移动、进食、增长以及死亡过程,并统计所得分数。游戏面板划分为许多小格,蛇移动时每次只移动一格。食物随机放置,但不能放到蛇身。每进食一次,蛇身增长一格,得分相应增加。蛇碰到边界时转到对面边界出来。当蛇头碰到自身时,蛇死亡,游戏结束。

游戏需求:

要有良好的可视化操作界面,有良好的声音效过。通过键盘鼠标控制,并且实现用户菜单及提示信息。游戏采用实时控制和动画刷新,保证系统稳定流畅运行。能够根据游戏规则自动判断游戏状态,并将信息实时反馈给用户。

概要设计:

游戏启动时显示游戏LOGO或加载信息,随后进入菜单界面,可选菜单要有:新的游戏、继续游戏、选择关卡、帮助及退出。游戏时,左边及中心显示游戏面板,右边显示信息栏。通过上下左右四个方向键控制蛇的移动,通过鼠标进行按钮的点击。游戏能够在任何时候暂停和退出游戏。通过关卡或者失败时,显示全屏的提示信息,并提供按钮供用户选择。游戏加入音乐功能模块,实现音效和背景音乐的播放。

环境要求:

Windows系统,Visual C++编译环境。

 

 

二、    功能模块结构

模块:

程序的主要模块有:游戏控制模块、资源管理模块、交互元素模块、游戏规则模块、绘图模块、音效模块、错误处理模块等。

        

模块

包含的类

功能

游戏控制模块

Game

主要负责游戏流程的控制,游戏元素的存储与组织,是整个游戏的控制中心。

 

资源管理模块

Manager

主要负责图片与音乐资源的统一管理、分配与调度。能够有效地集中资源节省空间、降低重复工作。

交互元素模块

ButtonGridRectSelBoxText

负责用户交互界面的处理与绘制。

游戏规则模块

FoodNodePanelSnake

控制游戏的规则。

绘图模块

PainterElebasePictureTileAnimationFullScrAni

用来绘图的类,包括绘图的操作和图元。

音效模块

Mid

对背景音乐进行加载与播放

错误处理模块

ErrorInit_ErrorOuter_Error

用来处理错误

 

类视图(详情请参见附件):

 

三、    主要模块的算法说明:

游戏控制模块:

游戏控制类的成员包含有窗口的基本信息,游戏资源管理类对象,面板类对象。在窗口建立好后接着构造游戏控制类,实现对其他部分类的初始化工作,并调用资源管理类进行资源的加载以及绘图设备的初始化。

游戏控制类采用状态进行驱动,通过改变记录状态的变量实现流程的跳转。

在游戏开始进行时,游戏控制模块负责面板的创建,从而建立起游戏规则类对象。游戏控制类接管了窗口的定时器消息,定时对游戏进行更新。许多页面的显示,例如菜单页面、成功页面、失败页面、帮助信息页面都由游戏控制类负责。

此外,游戏控制类实现了游戏存档的读取与保存。

资源管理模块:

资源管理模块用Manager类实现,Manager类依赖Picture类、Tile类、Animation类和Mid类,用四个顺序容器分别储存四个类的对象,实现资源的统一管理。此外Manager类实现了对背景音乐的控制。

交互元素模块:

Elebase为虚基类,只要能在屏幕上画出来的都看做交互元素,每个交互元素必须与一个动画对象相关联,且都从Elebase依次多层继承下去。Elebase类储存有动画指针,提供的绘图的虚函数。

游戏规则模块:

游戏规则模块是游戏的核心,它构成了一个独立的系统,控制着游戏的运行。能读取键盘按键状态,并将游戏跳转信息发给游戏控制模块。游戏规则模块包括Food类、Node类、Panel类、Snake类,Food类保存食物信息并随机产生食物,Node类为蛇的节点类,Panel类是游戏的控制类,实现游戏的更新与画面的刷新,并检测游戏的状态。此外Panel有一Snake类的子对象。Panel类通过检测按键,向Snake类发送改变方向的消息,并让其移动。在每一帧中,Panel会检测蛇的长度、蛇是否已撞到自身,从而做出相应的响应。蛇的身体由一个Node顺序容器构成,Node类包含的成员主要有坐标、方向。蛇移动时,从尾开始,每个节点的位置都移动到下一个节点位置,最后一个节点(即蛇头)则根据蛇的方向移动。

绘图模块:

本游戏通过Windows GDI实现图形的绘制。其基本绘图过程为:加载位图、创建兼容设备,位块传输。由于考虑到游戏的刷新率较高,直接绘图会产生闪动的现象,所以采用了双缓冲技术。双缓冲的基本原理是:把图画全部画到缓冲设备上,再在最后一次性位块传输到原设备上。

音效模块:

游戏中采用wav声音作为普通的短暂的音效,这种音效的播放分散在程序的各个地方。具体的播放方法是调用PlaySound函数,即时加载即时播放。对于背景音乐,则采用mid格式文件。mid文件具有格式小,播放简单的特点,其实现方法是调用mciSendCommand函数。

错误处理模块:

错误处理类用来供程序抛出与捕捉程序,主要的类有Error基类、Init_Error类、Outer_Error类。通过错误处理模块,程序能够有序地处理错误。

 

 

四、    游戏运行效果:

 

 

 

 

五、    总结:

这是迄今为止,我用C++做过的最复杂的程序。程序总共大约一千五百行,拥有类21个。在程序设计的过程中,我遇到了许许多多的问题,但可喜的是,通过请教老师同学以及网上寻求帮助,这些问题最终都被解决了。主要遇到的问题有以下这些:如何组织资源、如何播放MID、怎样解决重载的二义性问题、怎样实现双缓冲等等。对于组织资源问题,我询问了许多网友,他们都一致认为资源应该集中加载与管理,这样有利于提高效率和节约空间。播放MID 的问题,我通过查阅Windows编程的书籍,发现其实MID的播放并不难,已经有现成的API可以调用。重载的二义性问题我也曾经遇到过,也曾经和同学探讨过,当时的解决方案是用强制转换类型避免二义性。但是这一次我遇到的问题不能通过强制转换来解决,幸运的是,在The C++ ProgrammingLanguage上面我成功地找到了解决办法,只要在类的构造函数前加一个explicit关键字,禁止默认的类型转换就能避免二义性。双缓冲技术曾经听说过,也写过DEMO,但由于双缓冲技术较为复杂,一时之间竟然不能很好地实现,所幸的是网上有许许多多关于双缓冲的介绍,通过阅读技术博客,我在游戏中顺利地实现了双缓冲。

在这个程序的编写过程中,我学到了许许多多知识,特别是学会了STLWindows API。我认识到了软件的开发是一个庞大的复杂的工程,要实现这个工程,不仅需要很好的技术,更需要良好的组织与管理。我与许多同学交流过这方面的经验,发现一个项目的成功与失败,取决的往往不是技术的高低,而是工程的策划管理以及模块的划分是不是很到位。由此,我认识到了软件工程的重要性,并决心以后要学好软件工程。

六、    参考文献:

The C++ Programming Language——()Bjarne Stroustrup

Windows程序设计——CharlesPetzold

MSDN

七、    附录:

类视图

关系图

 

程序清单(详情请查看工程文件)

 

//****************global.h  全局类、枚举、常量的声明*********************************

#pragmaonce

#pragmawarning(disable:4786)

#include<windows.h>

#include<string>

usingstd::string;

 

//--------------------错误处理类------------------------------

classError

{

string info;

public:

Error(conststring& sinf):info(sinf){}

voidMsgBox(){MessageBox(NULL,info.c_str(),"错误",MB_OK);}

};

 

classInit_Error:publicError

{

public:

Init_Error(conststring& sinf):Error(sinf){}

};

 

classOuter_Error:publicError

{

public:

Outer_Error(conststring& sinf):Error(sinf){}

};

 

//-------------------Enums--------------------------------

enumANITYPE{ANI_LOGO=0,ANI_MENUBK,ANI_SNAKE_HEAD,ANI_SNAKE_BODY,ANI_SNAKE_TAIL,ANI_FOOD,ANI_BACKGROUND,

ANI_WIN,ANI_FAIL,ANI_BUTTON,ANI_OUTLINE,ANI_SELBKGROUND,ANI_HELP};

enumANIBACKGROUND{ANI_BACKGROUND_GRASS,ANI_BACKGROUND_WOOD,ANI_BACKGROUND_ROCK,ANI_BACKGROUND_TILE};

enumANIBUTTON{ANI_BUTTON_NEW,ANI_BUTTON_OLD,ANI_BUTTON_SEL,ANI_BUTTON_HELP,ANI_BUTTON_QUIT,

ANI_BUTTON_CONTINUE,ANI_BUTTON_BACK,ANI_BUTTON_LEFT,ANI_BUTTON_RIGHT,ANI_BUTTON_OK,ANI_BUTTON_CANCEL,

ANI_BUTTON_PAUSE,ANI_BUTTON_RECOVER,ANI_BUTTON_RETURN};

                                                                                     

enumMID{MID_MENUBKM,MID_MAP0};

 

enumDIRECTION{RIGHT=0,DOWN=1,LEFT=2,UP=3};

 

//------------------const------------------------------

 

constintFPS=30;

 

 

//*********************贪吃蛇.cpp ******************************

//窗体的创建、消息的处理

#include<windows.h>

#include<stdlib.h>

#include<malloc.h>

#include<memory.h>

#include<tchar.h>

#include"resource.h"

#include"manager.h"

 

//全局变量

HINSTANCE hInst;

Game* pGame;

 

//函数声明

ATOM                                   MyRegisterClass(HINSTANCE hInstance);

BOOL                                    InitInstance(HINSTANCE, int);

LRESULTCALLBACK    WndProc(HWND,UINT, WPARAM, LPARAM);

 

//主函数

intAPIENTRY WinMain(HINSTANCEhInstance,

                     HINSTANCEhPrevInstance,

                     LPSTR     lpCmdLine,

                     int       nCmdShow)

{

MSG msg;

MyRegisterClass(hInstance);

 

// 程序初始化

if(!InitInstance (hInstance, nCmdShow))returnFALSE;

//消息转发

while (GetMessage(&msg, NULL, 0, 0))

{

          TranslateMessage(&msg);

          DispatchMessage(&msg);

}

returnmsg.wParam;

}

 

//注册窗口类

ATOM MyRegisterClass(HINSTANCEhInstance)

{

WNDCLASSEX wcex;

 

wcex.cbSize = sizeof(WNDCLASSEX); 

 

wcex.style                            =CS_HREDRAW | CS_VREDRAW;

wcex.lpfnWndProc   = (WNDPROC)WndProc;

wcex.cbClsExtra                =0;

wcex.cbWndExtra             =0;

wcex.hInstance                  =hInstance;

wcex.hIcon                          =LoadIcon(hInstance, (LPCTSTR)IDI_MY);

wcex.hCursor             =LoadCursor(hInstance, (LPCTSTR)IDC_CUR);

wcex.hbrBackground        = (HBRUSH)(COLOR_WINDOW+1);

wcex.lpszMenuName        = NULL;(LPCSTR)IDC_MY;

wcex.lpszClassName         = "SnakeWindow";

wcex.hIconSm          =LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

 

returnRegisterClassEx(&wcex);

}

 

//初始化程序

BOOL InitInstance(HINSTANCEhInstance,intnCmdShow)

{

   HWNDhWnd;

 

   hInst = hInstance;

 

   hWnd = CreateWindowEx((unsigned)NULL,"SnakeWindow","Snake", WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,

      CW_USEDEFAULT,0, 800+GetSystemMetrics(SM_CXFIXEDFRAME)*2,

 600+GetSystemMetrics(SM_CXFIXEDFRAME)*2+GetSystemMetrics(SM_CYCAPTION), NULL, NULL, hInstance, NULL);

 

   if (!hWnd)returnFALSE;

 

   ShowWindow(hWnd, nCmdShow);

   UpdateWindow(hWnd);

 

   //创建游戏

pGame=newGame(hInst,hWnd,800,600);

//设置定时器

SetTimer(hWnd,0,1000/FPS,NULL);

 

 

   returnTRUE;

}

 

//消息处理

LRESULTCALLBACKWndProc(HWNDhWnd,UINTmessage, WPARAMwParam, LPARAMlParam)

{

PAINTSTRUCT ps;

HDC hdc;

 

switch (message)

{

          caseWM_PAINT:

                    hdc = BeginPaint(hWnd,&ps);

                    EndPaint(hWnd,&ps);

                    break;

          caseWM_TIMER:

                    pGame->Loop();

                    break;

          caseWM_DESTROY:

                    deletepGame;

                    PostQuitMessage(0);

                    break;

          default:

                    returnDefWindowProc(hWnd, message,wParam,lParam);

   }

   return 0;

}

 

 

 

//*********************element.h**************************

//包括了用户交互元素的类、绘图的类以及游戏规则类

#pragmaonce

#include"global.h"

#include"manager.h"

#include"paint.h"

#include<sstream>

#include<fstream>

#include<vector>

#include<string>

usingnamespacestd;

 

classPainter;

classManager;

classAnimation;

classNode;

classPanel;

classSnake;

 

//运算符重载声明

ofstream& operator<<(ofstream&ofs,constPanel&panel);

ifstream& operator>>(ifstream&ifs,Panel& panel);

ofstream& operator<<(ofstream&ofs,constSnake&snake);

ifstream& operator>>(ifstream&ifs,Snake& snake);

ofstream& operator<<(ofstream&ofs,constNode&node);

ifstream& operator>>(ifstream&ifs,Node& node);

 

classElebase//元素虚基类

{

protected:

staticPainter *pPainter;

staticManager *pManager;

Animation *pAni;

public:

void SetAni(Animation *pani){pAni=pani;}

virtualvoidSetAni(int id1,intid2=-1,int id3=-1);

staticvoidPreInit(Painter *pP,Manager *pM){pPainter=pP;pManager=pM;}

Elebase():pAni(NULL){if(!pPainter|| !pManager)throwInit_Error("元素类未初始化!");}

virtualvoidDraw()=0;

Animation* Ani(){returnpAni;}

};

 

classRect:publicElebase//矩形类

{

protected:

intx,y,w,h;

public:

virtualvoidDraw();

Rect(intrx,intry,intrw,intrh):x(rx),y(ry),w(rw),h(rh){}

};

 

classFullScrAni:publicRect//全屏动画类

{

staticintflscrw,flscrh;

public:

staticvoidPreInit(int w,inth);

FullScrAni():Rect(0,0,flscrw,flscrh){}

};

 

classText:publicRect//文字输出类

{

friendclassPainter;

string str;

HFONT font;

DWORD color;

public:

Text(int rx,intry,int rw,intrh,constchar*face="宋体");

~Text(){if(font)DeleteObject(font);}

voidSetText(conststring&tex,DWORDtexcolor=RGB(0,0,0)){str=tex;color=texcolor;};

voidSetText(intnum,DWORDtexcolor=RGB(0,0,0)){ostringstreamss;ss<<num;str=ss.str();color=texcolor;}

void Draw();

};

 

classButton:publicRect//按钮类

{

staticHWND hwnd;

 

bool focus;

boolkeydown;

boolpressed;

intorgx,orgy,orgw,orgh;

voidEnLarge(intpx=6){x-=px;w+=2*px;y-=px;h+=2*px;}

void Shift(intpx=2){x+=px;y+=px;}

voidEnNormal(){x=orgx;y=orgy;w=orgw;h=orgh;}

public:

staticvoidPreInit(HWNDhWnd){hwnd=hWnd;}

Button(intbx,int by,intbw=200,int bh=50);

void Deal();

boolMousePressed(){return pressed;}

voidRecover(){focus=false;keydown=false;pressed=false;EnNormal();}

};

 

classSelBox:publicRect//选择框类

{

Buttonleftbutton;

Buttonrightbutton;

Text tex;

vector<string> strlist;

int curstr;

public:

SelBox(intsx,int sy,intsw,int sh,floatscale=1);//scale为文本和按钮的大小比

void Deal();

voidSelBox::SetAni(int psb1,intplb1,int prb1,intpsb2=-1,int plb2=-1,intprb2=-1,int psb3=-1,intplb3=-1,int prb3=-1);

SelBox&Add(conststring&str){strlist.push_back(str);return*this;}

SelBox&Add(intnum){ostringstream ss;ss<<num;strlist.push_back(ss.str());return*this;}

string&str(){return strlist[curstr];}

void Draw();

};

 

classSnake//蛇类

{

friendclassPanel;

int rate;              //移动一次所占帧数

intcurratepos;  //移动之后过去的帧数

intdirection;     //方向

intnewdirect;    //新方向

bool added;                //遇到食物是否已添加

bool live;           //活的

vector<Node*> nodes;

public:

Snake(int lenth,intv,int startx=10,intstarty=10,int direc=RIGHT);

~Snake();

bool Move();//移动返回真,未移动返回假

boolIsBumpFood(int fx,intfy);

boolIsBumpSelf();

boolIsLive(){return live;}

voidRight(){if(direction!=LEFT)newdirect=RIGHT;}

void Down(){if(direction!=UP)newdirect=DOWN;}

void Left(){if(direction!=RIGHT)newdirect=LEFT;}

void Up(){if(direction!=DOWN)newdirect=UP;}

voidAddNode();

void Draw();

intlenth(){return nodes.size();}

 

Node*Head(){return nodes[0];}

//判断指定坐标是否在蛇上

inlineboolOnHead(int x,inty);

inlineboolOnBelly(int x,inty);

inlineboolOnBody(int x,inty);

inlineboolOnTail(int x,inty);

boolOnSnake(intx,inty){returnOnBody(x,y)||OnHead(x,y);}

 

inlineintHeadX();

inlineintHeadY();

 

//重载   用于存档

friendofstream& operator<<(ofstream&ofs,constSnake&snake);

friendifstream& operator>>(ifstream&ifs,Snake& snake);

 

};

 

classGrid:publicElebase//格子类

{

friendclassPanel;

friendclassSnake;

protected:

staticintpx,py,gw,gh;

int gx,gy;

public:

staticvoidPreInit(intpanelx,intpanely,intgridw,intgridh)

{px=panelx;py=panely;gw=gridw;gh=gridh;}

Grid(intgridx,intgridy):gx(gridx),gy(gridy){}

void Draw();

};

 

classFood:publicGrid//食物类

{

friendclassPanel;

intmaxx,maxy;

public:

Food(intxnum,intynum):Grid(0,0),maxx(xnum),maxy(ynum){}

voidGenerate()

{

          gx=rand()%maxx;

          gy=rand()%maxy;

}

friendofstream& operator<<(ofstream&ofs,constPanel&panel);

friendifstream& operator>>(ifstream&ifs,Panel& panel);

};

 

classNode:publicGrid//节点类  也即蛇的节点

{

friendclassSnake;

intdirection;

public:

Node(intgridx,intgridy,intdirect=RIGHT):Grid(gridx,gridy),direction(direct){}

int X(){returngx;}

int Y(){returngy;}

intDirection(){return direction;}

 

friendofstream& operator<<(ofstream&ofs,constNode&node);

friendifstream& operator>>(ifstream&ifs,Node& node);

 

};

 

classPanel:publicRect      //游戏面板类

{

intxnum,ynum;

Snake *snake;

Food food;

bool overed;

bool won;

int level;

int score;

 

bool pause;

voidChkBump();

public:

explicit Panel(intLevel,int rectx=100,intrecty=100,int rectw=450,intrecth=450,int gridxnum=20,intgridynum=20);

~Panel(){if(snake){deletesnake;snake=NULL;}}

voidDoFrame();

boolOvered(){return overed;}

bool Won(){returnwon;}

intScore(){return score;}

intRestFood();

voidSetPause(boolp){pause=p;}

boolIsPause(){return pause;}

 

friendofstream& operator<<(ofstream&ofs,constPanel&panel);

friendifstream& operator>>(ifstream&ifs,Panel& panel);

};

 

 

 

 

//*******************element.cpp**********************

//

 

#include"element.h"

usingnamespacestd;

#pragmacomment(lib,"Winmm.lib")

 

Painter* Elebase::pPainter=NULL;

Manager *Elebase::pManager=NULL;

intFullScrAni::flscrw=0;

intFullScrAni::flscrh=0;

HWNDButton::hwnd=NULL;

 

voidElebase::SetAni(intid1,intid2,intid3)

{

pAni=pManager->PickAni(id1,id2,id3);

}

 

voidRect::Draw()

{

if(!pAni)return;

if(!pAni->Stoped())pPainter->Draw(*pAni,x,y,w,h);

pAni->Refresh();

}

 

 

intGrid::px=0,Grid::py=0,Grid::gw=0,Grid::gh=0;

 

voidGrid::Draw()

{

if(!pAni) throwInit_Error("格子类动画未初始化!");

if(!pAni->Stoped())pPainter->Draw(*pAni,px+gx*gw,py+gy*gh,gw,gh);

pAni->Refresh();

}

 

Text::Text(intrx,intry,intrw,intrh,constchar*face):Rect(rx,ry,rw,rh),font(NULL)

{

if(font)DeleteObject(font);

//创建字体画笔

font=CreateFont(h,w,0,0,FW_NORMAL,false,false,false,

                                      CHINESEBIG5_CHARSET,OUT_CHARACTER_PRECIS,

                                      CLIP_CHARACTER_PRECIS,DEFAULT_QUALITY,

                                      FF_MODERN,"face");

}

 

voidText::Draw()

{

if(pAni)Rect::Draw();

pPainter->Draw(*this,x,y);

}

 

 

//--------------------------------------Button------------------------

Button::Button(intbx,intby,intbw,intbh)

:Rect(bx,by,bw,bh),focus(false),keydown(false),

pressed(false),orgx(bx),orgy(by),orgw(bw),orgh(bh)

{

}

 

voidButton::Deal()//处理按钮的响应事件

{

if(!hwnd)throwInit_Error("按钮类未获得窗口句柄!");

POINT point;

//获取鼠标指针坐标

GetCursorPos(&point);

ScreenToClient(hwnd,&point);

EnNormal();

if(point.x>x&&point.x<x+w&&point.y>y&&point.y<y+h)

{    //判断鼠标指针是否在按钮区域内

          if(!focus)PlaySound("data\\mouseon.wav",NULL,SND_FILENAME|SND_ASYNC);

          focus=true;

          EnLarge();

          if(GetAsyncKeyState(VK_LBUTTON))

          {  //鼠标左键是否按下

                    keydown=true;

                    Shift();

          }

          else

                    if(keydown)

                    {   

                             pressed=true;

                             keydown=false;

                             PlaySound("data\\click.wav",NULL,SND_FILENAME|SND_ASYNC);

                    }

}

else focus=false;

GetAsyncKeyState(VK_LBUTTON);

}

 

//-------------------SelBox

SelBox::SelBox(intsx,intsy,intsw,intsh,floatscale)

:Rect(sx,sy,sw,sh),leftbutton(sx,sy,int(sw/(scale+2)),sh),rightbutton(int(sx+sw-sw/(scale+2)),sy,int(sw/(scale+2)),sh),

tex(int(sx+sw/(scale+2)),sy,int(sw-2*sw/(scale+2)),sh),curstr(0)

{


}

voidSelBox::SetAni(intpsb1,intplb1,intprb1,intpsb2,intplb2,intprb2,intpsb3,intplb3,intprb3)

{

Elebase::SetAni(psb1,psb2,psb3);

leftbutton.SetAni(plb1,plb2,plb3);

rightbutton.SetAni(prb1,prb2,prb3);

}

voidSelBox::Deal()

{


leftbutton.Deal();

rightbutton.Deal();

if(leftbutton.MousePressed()&&curstr>0)

{   //针对左右按钮的按键做出响应

          curstr--;

          leftbutton.Recover();

}

if(rightbutton.MousePressed()&&curstr<int(strlist.size()-1))

{

          curstr++;

          rightbutton.Recover();

}

tex.SetText(strlist[curstr]);

}

 

voidSelBox::Draw()

{

if(pAni)Rect::Draw();

tex.Draw();

leftbutton.Draw();

rightbutton.Draw();

}

 

Snake::Snake(intlenth,intv,intstartx,intstarty,intdirec)

:rate(v),direction(direc),curratepos(0),added(false),live(true),

newdirect(RIGHT)

{

//蛇的构建

Node* head=newNode(startx--,starty);

head->SetAni(ANI_SNAKE_HEAD);

nodes.push_back(head);

for(inti=1;i<lenth-1;i++)

{

          Node*body=newNode(startx--,starty);

          body->SetAni(ANI_SNAKE_BODY);

          nodes.push_back(body);

}

Node* tail=newNode(startx--,starty);

tail->SetAni(ANI_SNAKE_TAIL);

nodes.push_back(tail);

}

 

Snake::~Snake()

{

//蛇的清除

for(inti=0;i<(int)nodes.size();i++)

          deletenodes[i];

nodes.clear();

}

 

intSnake::HeadX()

{

returnHead()->X();

}

 

intSnake::HeadY()

{

returnHead()->Y();

}

 

boolSnake::Move()//蛇的移动

{

if(!live) returnfalse;

curratepos+=1000/FPS;

if(curratepos>=rate)

{

          curratepos=0;

          inthx=Head()->gx;

          inthy=Head()->gy;

          direction=newdirect;

          //根据蛇的方向改变蛇头坐标

          switch(direction)

          {

                    caseRIGHT:

                             hx++;

                             break;

                    caseDOWN:

                             hy++;

                             break;

                    caseLEFT:

                             hx--;

                             break;

                    caseUP:

                             hy--;

                             break;

          }

          //移动

          for(vector<Node*>::iterator it=nodes.end()-1;it>nodes.begin();it--)   

          {

                    if(it==nodes.end()-1&& added)

                    {

                             added=false;

                             continue;

                    }

                    (*it)->gx=(*(it-1))->gx;

                    (*it)->gy=(*(it-1))->gy;

                    (*it)->direction=(*(it-1))->direction;

          }

          nodes[0]->gx=hx;

          nodes[0]->gy=hy;

          nodes[0]->direction=direction;

          returntrue;

}

returnfalse;

}

 

boolSnake::IsBumpFood(intfx,intfy)//自己增长

{

if(HeadX()==fx&& HeadY()==fy)//撞到食物

{

          AddNode();

          returntrue;

}

returnfalse;

}

 

boolSnake::IsBumpSelf()

{

if(OnBody(HeadX(),HeadY()))//撞到自己

{

          live=false;

}

return live;

}

 

voidSnake::AddNode()//蛇增加节点

{

Node*tail=nodes.back();

Node* body=newNode(tail->X(),tail->Y());

body->SetAni(ANI_SNAKE_BODY);

nodes.insert(nodes.end()-1,body);

added=true;

}

 

boolSnake::OnHead(intx,inty)

{

returnx==nodes[0]->gx&& y==nodes[0]->gy;

}

 

boolSnake::OnBody(intx,inty)//包括头和尾

{

return OnTail(x,y)||OnBelly(x,y);

}

 

boolSnake::OnTail(intx,inty)

{

returnx==nodes.back()->gx&& y==nodes.back()->gy;

}

 

boolSnake::OnBelly(intx,inty)//蛇的中间部分

{

for(vector<Node*>::iterator it=nodes.begin()+1;it<nodes.end()-1;it++)

          if(x==(*it)->gx&& y==(*it)->gy) returntrue;

returnfalse;

}

 

voidSnake::Draw() 

{

//循环把蛇身画出来

for(vector<Node*>::iterator it=nodes.begin();it<nodes.end();it++)

          (*it)->Draw();

}

 

Panel::Panel(intLevel,intrectx,intrecty,intrectw,intrecth,intgridxnum,intgridynum)

          :level(Level),Rect(rectx,recty,rectw,recth),xnum(gridxnum),ynum(gridynum),

          snake(NULL),food(xnum,ynum),overed(false),won(false),score(0),pause(false)

{

food.SetAni(ANI_FOOD);

food.Generate();

Grid::PreInit(x,y,w/xnum,h/ynum);

snake=newSnake(int(level*2),int(400/level));//创建蛇

 

SetAni(ANI_BACKGROUND,int(level/2+0.5)%9);//设置动画

}

 

voidPanel::DoFrame()

{

 

Draw();

food.Draw();

if(!pause)

{

          //检测按键

          if(GetAsyncKeyState(VK_RIGHT)) snake->Right();

          if(GetAsyncKeyState(VK_DOWN)) snake->Down();

          if(GetAsyncKeyState(VK_LEFT)) snake->Left();

          if(GetAsyncKeyState(VK_UP)) snake->Up();

 

          if(snake->Move())

          {

                    if(snake->HeadX()<0)snake->Head()->gx=xnum-1;

                    if(snake->HeadY()<0)snake->Head()->gy=ynum-1;

                    if(snake->HeadX()>=xnum)snake->Head()->gx=0;

                    if(snake->HeadY()>=ynum)snake->Head()->gy=0;

                    ChkBump();

          }

}

snake->Draw();

 

if(RestFood()<=0)//判断食物是否全部吃完

{

          overed=true;

          won=true;

          PlaySound("data\\win.wav",NULL,SND_FILENAME|SND_ASYNC);

}

}

 

intPanel::RestFood()

{

returnlevel*3+3-snake->lenth();

}

 

voidPanel::ChkBump()//碰撞检测

{

snake->IsBumpSelf();

if(snake->IsBumpFood(food.gx,food.gy))//蛇是否撞到食物

{

          score+=level*10;

          PlaySound("data\\eat.wav",NULL,SND_FILENAME|SND_ASYNC);

          do

          {

                    boolonsnake=false;

                    food.Generate();

          }while(snake->OnSnake(food.gx,food.gy));

}

if(!snake->IsLive())//蛇是否是活的

{

          overed=true;

          won=false;

          PlaySound("data\\fail.wav",NULL,SND_FILENAME|SND_ASYNC);

}

}

 

//以下是运算符重载,用于存档的读取与储存

ofstream& operator<<(ofstream&ofs,constNode& node)

{

ofs<<node.gx<<endl<<node.gy<<endl<<node.direction<<endl;

returnofs;

}

 

ifstream& operator>>(ifstream&ifs,Node& node)

{

ifs>>node.gx>>node.gy>>node.direction;

returnifs;

}

 

ofstream& operator<<(ofstream&ofs,constSnake& snake)

{

ofs<<snake.rate<<endl<<snake.direction<<endl<<snake.newdirect<<endl;

for(vector<Node*>::const_iterator it=snake.nodes.begin();it<snake.nodes.end();it++)

          ofs<<(**it);

returnofs;

}

 

ifstream& operator>>(ifstream&ifs,Snake& snake)

{

ifs>>snake.rate>>snake.direction>>snake.newdirect;

 

for(vector<Node*>::const_iterator it=snake.nodes.begin();it<snake.nodes.end();it++)

{

          ifs>>**it;

}

returnifs;

}

 

 

ofstream& operator<<(ofstream&ofs,constPanel& panel)

{

ofs<<panel.xnum<<endl<<panel.ynum<<endl

          <<panel.food.gx<<endl<<panel.food.gy<<endl

          <<panel.level<<endl<<panel.score<<endl;

ofs<<*panel.snake;

returnofs;

}

 

ifstream& operator>>(ifstream&ifs,Panel& panel)

{

ifs>>panel.xnum>>panel.ynum

>>panel.food.gx>>panel.food.gy

>>panel.level>>panel.score;

ifs>>*panel.snake;

returnifs;

}

 

 

 

 

//*******************paint.h**************************

//主要包含绘图的模块

#pragmaonce

#include"global.h"

#include"manager.h"

#include"element.h"

#include<windows.h>

#include<vector>

 

 

usingstd::vector;

 

classText;

 

classPicture//图片类

{

friendclassPainter;

HDC hdc;

HBITMAP hbmp;

int w,h;

staticHINSTANCE hInst;

staticHDC horgdc;

public:

staticvoidPreInit(HINSTANCE hInstance,HDChoriginaldc);

Picture(constchar*picfile);

~Picture();

};

 

classTile//贴片类,即图片上的一块矩形区域

{

friendclassPainter;

Picture *pPic;

intpicx,picy,tilew,tileh;

public:

Tile(Picture*ppic,intx,inty,intw,inth)

          :pPic(ppic),picx(x),picy(y),tilew(w),tileh(h)

{if(ppic<0||x<0||y<0||w<=0||h<=0)throwInit_Error("贴片类初始化失败!");}

virtualconstTile& GetTile()const{return*this;}

Picture* Pic(){returnpPic;}

};

 

classAnimation//动画类,由许多贴片构成动画

{

friendclassPainter;

vector<Tile*> tilepv;

//

int cycl;    

intinterval;

int  pos;

intintervalpos;

intcyctimes;

bool stoped;

public:

Animation(intcyc,intitvl):cycl(cyc),interval(itvl),pos(0),cyctimes(0),intervalpos(0),stoped(false)

{if(cyc<0||itvl<0)throwInit_Error("动画类初始化失败!");}

voidAddTile(Tile* tile){tilepv.push_back(tile);}

voidRefresh();

voidRestart(){pos=0;intervalpos=0;cyctimes=0;stoped=false;}

constTile& GetTile()const {return*tilepv[pos];}

boolStoped()const{returnstoped;}

};

 

classPainter//负责画图的类

{

HDChcompdc;

HDC hdc;

HBITMAPhcompbmp;

intx,y,w,h;

DWORDbkcolor;

public:

Painter(HDChDC,int cx,intcy,int cw,intch);

~Painter();

void Draw(constTile& tile,int x,inty);

void Draw(constAnimation& ani,int x,inty);

void Draw(constAnimation& ani,int x,inty,int w,inth);

void Draw(constText& tex,int x,inty);

voidErase();

voidApply();

};

 

 

 

//*********************paint.cpp**************************

 

#include"paint.h"

#pragmacomment(lib,"Msimg32.lib")

//---------------Picture-----------------------

HINSTANCEPicture::hInst=NULL;

HDCPicture::horgdc=NULL;

 

//预先初始化函数,由于该类需要在构造时知道某些必要参数,并且对于所有对象,这些参数

//都相同,所以采用静态成员预先初始化的方法

voidPicture::PreInit(HINSTANCEhInstance,HDChoriginaldc)

{

hInst=hInstance;

horgdc=horiginaldc;

}

 

Picture::Picture(constchar*picfile):hdc(NULL),hbmp(NULL)

{

//图片的加载

if(!hInst|| !horgdc) throwInit_Error("图片类未预初始化!");

hbmp=(HBITMAP)LoadImage(hInst,picfile,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_LOADFROMFILE);

if(!hbmp)throwOuter_Error("加载图片失败!");

hdc=CreateCompatibleDC(horgdc);

if(!hdc)throwOuter_Error("创建兼容设备失败!");

SelectObject(hdc,hbmp);

BITMAP bmp;

if(!GetObject(hbmp,sizeof(BITMAP),&bmp))throwOuter_Error("获取图片信息失败!");

w=bmp.bmWidth;

h=bmp.bmHeight;

}

 

Picture::~Picture()

{

if(hdc)DeleteObject(hdc);

if(hbmp)DeleteObject(hbmp);

}

 

 

//---------------Animation-------------------

voidAnimation::Refresh()

{

//动画的控制

if(intervalpos<interval)

{

          intervalpos++;

          return;

}

else

{

          intervalpos=0;

}

if(pos<(int)tilepv.size()-1&& !stoped)

{

          pos++;

}

else

{

          pos=0;

          if(cycl!=0)

          {

                    cyctimes++;

                    if(cyctimes>=cycl)

                             stoped=true;

          }

}

}

 

//--------------------Painter----------------------------

Painter::Painter(HDChDC,intcx,intcy,intcw,intch):hdc(hDC),hcompdc(NULL),hcompbmp(NULL),x(cx),y(cy),w(cw),h(ch)

{

//采用双缓冲,建立缓冲区

hcompdc=CreateCompatibleDC(hdc);

hcompbmp=CreateCompatibleBitmap(hdc,w,h);

SelectObject(hcompdc,hcompbmp);

}

 

Painter::~Painter()

{

if(hcompdc)

{

          DeleteDC(hcompdc);

          hcompdc=NULL;

}

if(hcompbmp)

{

          DeleteObject(hcompbmp);

          hcompbmp=NULL;

}

}

 

voidPainter::Draw(constTile& tile,intx,inty)

{

//位块传输,用来贴图

BitBlt(hcompdc,x,y,tile.tilew,tile.tileh,tile.pPic->horgdc,tile.picx,tile.picy,SRCCOPY);

}

 

voidPainter::Draw(constAnimation& ani,intx,inty)

{

if(ani.Stoped())return;

constTile& tile=ani.GetTile();

BitBlt(hcompdc,x,y,tile.tilew,tile.tileh,tile.pPic->hdc,tile.picx,tile.picy,SRCCOPY);

}

 

voidPainter::Draw(constAnimation& ani,intx,inty,intw,inth)

{

if(ani.Stoped())return;

constTile& tile=ani.GetTile();

//过滤透明色的位块传输

TransparentBlt(hcompdc,x,y,w,h,tile.pPic->hdc,tile.picx,tile.picy,tile.tilew,tile.tileh,RGB(0,0,0));

}

 

voidPainter::Draw(constText& tex,intx,inty)

{

//绘制文字

SetBkMode(hcompdc,TRANSPARENT);

SetTextColor(hcompdc,tex.color);

SelectObject(hcompdc,tex.font);

TextOut(hcompdc,x,y,tex.str.c_str(),tex.str.length());

}

 

voidPainter::Erase()

{

//对整个绘图区域进行擦除

HBRUSHbrush=CreateSolidBrush(bkcolor);

SelectObject(hcompdc,brush);

RECTrect={x,y,x+w,y+h};

FillRect(hcompdc,&rect,brush);

DeleteObject(brush);

}

 

voidPainter::Apply()

{

//把缓冲页面的内容贴到屏幕设备上

BitBlt(hdc,x,y,w,h,hcompdc,0,0,SRCCOPY);

}

 

 

//**********************manager.h*******************

//管理模块

 

#pragmaonce

#include"global.h"

#include"paint.h"

#include"element.h"

 

#include<fstream>

#include<string>

#include<vector>

 

usingstd::string;

usingstd::fstream;

usingstd::vector;

 

classPicture;

classTile;

classAnimation;

classPainter;

classPanel;

classMid;

 

classManager

{

typedefvector<Picture*> PICPV;

typedefvector<Tile*> TILEPV;

typedefvector<Animation*> ANIPV;

typedefvector<Mid*> MIDPV;

//用顺序容器储存所有的图片与背景音乐资源

PICPV pics;

TILEPV    tiles;

ANIPV anis;

MIDPV mids;

int curmid;

public:

Manager():curmid(-1){}

~Manager();

void Add(conststring& picfile);//添加图片

void Add(Picture *ppic,int x,inty,int w,inth);//添加贴片

void Add(intpicid,int x,inty,int w,inth);//添加贴片

void Add(constvector<int>&tilevct,int cycl,intinterval);//添加动画

void AddMid(conststring& midfile);

void Add(intaniIndex);//添加单次循环动画

Animation&Ani(intid){return*anis.at(id);}

voidLoadRes();

voidLoadMid();

Animation*PickAni(int p1,intp2=-1,int p3=-1);

Mid*PicMid(int id);

void Play(intid);

void Stop();

};

 

classGame

{

//游戏状态

enumGAMESTATE{GAME_SHOWLOGO,GAME_SHOWMENU,GAME_SHOWHELP,GAME_CREATE,GAME_RESTART,GAME_RUN,GAME_DESTROY,GAME_WIN,GAME_FAIL,GAME_OVER};

GAMESTATE state;

 

HDChclientdc;

HWNDhWindow;

Painter*pPainter;

intclientw,clienth;

Managermanager;

 

int level;

introundtime;//每一局流逝的时间

voidShowLogo();

voidShowMenu();

voidShowWin();

voidShowFail();

voidShowOver();

voidShowHelp();

voidCreate();

voidReStart();

void Run();

voidDestroy();

 

voidReadArchive();

voidSaveArchive();

///////////////////Game Element///////////////////

Panel*pPanel;

public:

Game(HINSTANCEhinst,HWND hwnd,intclw,int clh);

~Game();

void Loop();


};

 

classMid//mid背景音乐处理的类

{

stringfilename;

UINTwDeviceID;

public:

Mid(conststring& fname);

~Mid();

void Play();

void Stop();

};

 

 

 

//*********************manager.cpp*******************

 

#include"manager.h"

#include"element.h"

#include<time.h>

#include<iterator>

usingnamespacestd;

#include<mmsystem.h>

#include<Digitalv.h>

#pragmacomment(lib,"Msimg32.lib")

#pragmacomment(lib,"winmm.lib")

 

voidFullScrAni::PreInit(intw,inth)

{

flscrw=w;

flscrh=h;

}

 

//-------------------Game-----------------------------

 

Game::Game(HINSTANCEhinst,HWNDhwnd,intclw,intclh)

:clientw(clw),clienth(clh),pPanel(NULL),level(0),pPainter(NULL),hclientdc(NULL),hWindow(hwnd),

roundtime(0)

{

srand((unsignedint)time(0));

 

hclientdc=GetDC(hWindow);

pPainter=newPainter(hclientdc,0,0,clientw,clienth);

//PreInit

Picture::PreInit(hinst,hclientdc);

Elebase::PreInit(pPainter,&manager);

FullScrAni::PreInit(clientw,clienth);

Button::PreInit(hwnd);


//加载资源

try

{

          manager.LoadRes();

          ShowLogo();

          pPainter->Apply();

          manager.LoadMid();

}

catch(Error err)

{

          err.MsgBox();

}

state=GAME_SHOWMENU;

}

 

Game::~Game()

{

if(hclientdc)ReleaseDC(hWindow,hclientdc);

if(pPanel){deletepPanel;pPanel=NULL;}

if(pPainter){deletepPainter;pPainter=NULL;}

}

 

voidGame::Create()

{

if(pPanel)deletepPanel;

//创建游戏面板

pPanel=newPanel(level);

manager.Play(MID_MAP0);

state=GAME_RUN;

roundtime=0;

}

 

voidGame::ShowWin()//显示胜利信息

{

staticFullScrAni ani;

staticButton butcont(clientw/2-100,clienth*4/5);


ani.SetAni(ANI_WIN);

ani.Draw();

butcont.SetAni(ANI_BUTTON,ANI_BUTTON_CONTINUE);

butcont.Deal();

butcont.Draw();

if(butcont.MousePressed())

{

          butcont.Recover();

          state=GAME_RESTART;

          level++;

          ani.Ani()->Restart();

}

}

 

voidGame::ShowFail()//显示失败信息

{

staticFullScrAni ani;

staticButton butcont(clientw*4/5-200,clienth*4/5);

staticButton butback(clientw/5,clienth*4/5);

 

ani.SetAni(ANI_FAIL);

ani.Draw();

butcont.SetAni(ANI_BUTTON,ANI_BUTTON_CONTINUE);

butcont.Deal();

butcont.Draw();

butback.SetAni(ANI_BUTTON,ANI_BUTTON_BACK);

butback.Deal();

butback.Draw();

if(butcont.MousePressed())

{

          butcont.Recover();

          state=GAME_RESTART;

          ani.Ani()->Restart();

}

elseif(butback.MousePressed())

{

          butback.Recover();

          level=1;

          Destroy();

          state=GAME_SHOWMENU;

}

}

 

voidGame::ShowOver()//显示游戏结束

{

Destroy();

state=GAME_SHOWMENU;

}

 

voidGame::Destroy()//销毁游戏成员对象

{

if(pPanel)

{

          deletepPanel;

          pPanel=NULL;

}

}

 

voidGame::Loop()//游戏的循环,由窗口的WM_TIMER消息引发

{

pPainter->Erase();

try

{

          //根据游戏状态控制游戏流程

          switch(state)

          {

          caseGAME_SHOWMENU:

                    ShowMenu();

                    break;

          caseGAME_SHOWHELP:

                   ShowHelp();

                    break;

          caseGAME_CREATE:

                    Create();

                    break;

          caseGAME_RUN:

                    Run();

                    break;

          caseGAME_DESTROY:

                    Destroy();

                    break;

          caseGAME_RESTART:

                    ReStart();

                    break;

          caseGAME_WIN:

                    ShowWin();

                    break;

          caseGAME_FAIL:

                    ShowFail();

                    break;

          caseGAME_OVER:

                    break;

          }

                    

}catch(Error err)

{

          err.MsgBox();

}

pPainter->Apply();

}

 

voidGame::ReStart()

{

Destroy();

Create();

}

 

voidGame::Run()//游戏运行

{

//界面元素的创建

staticFullScrAni outline;

staticText texlevel(675,217,20,20);

staticText texfood(675,300,20,20);

staticText texscore(675,387,20,20);

 

staticButton butpause(628,500,100,50);

staticButton butret(740,40,50,50);

//界面元素动画的设置

butpause.SetAni(ANI_BUTTON,pPanel->IsPause()?ANI_BUTTON_RECOVER:ANI_BUTTON_PAUSE);

butret.SetAni(ANI_BUTTON,ANI_BUTTON_RETURN);

 

outline.SetAni(ANI_OUTLINE);

//响应

butpause.Deal();

butret.Deal();

if(butpause.MousePressed())

{//是否暂停

          butpause.Recover();

          pPanel->SetPause(!pPanel->IsPause());

}

 

outline.Draw();

pPanel->DoFrame();

//绘制

butpause.Draw();

butret.Draw();

 

texlevel.SetText(level,RGB(255,255,255));

texscore.SetText(pPanel->Score(),RGB(255,255,255));

texfood.SetText(pPanel->RestFood(),RGB(255,255,255));

texlevel.Draw();

texscore.Draw();

texfood.Draw();

if(pPanel->Overed())

{

          if(pPanel->Won())state=GAME_WIN;

          elsestate=GAME_FAIL;

          manager.Stop();

}

if(butret.MousePressed())

{

          butret.Recover();

          Destroy();

          state=GAME_SHOWMENU;

}


roundtime+=1000/FPS;

if(roundtime%1000<1000/FPS)//每秒储存一次

          SaveArchive();

}

 

voidGame::ShowHelp()//显示帮助信息

{

staticFullScrAni helppage;

staticButton helpback(clientw*3/4-30,clienth*7/8,200,50);

helppage.SetAni(ANI_HELP);

helpback.SetAni(ANI_BUTTON,ANI_BUTTON_BACK);


helpback.Deal();

helppage.Draw();

helpback.Draw();

if(helpback.MousePressed())

{

          helpback.Recover();

          state=GAME_SHOWMENU;

}

}

 

voidGame::ShowMenu()//显示菜单

{

staticboolfirstrun=true;

//创建界面元素

staticFullScrAni menubk;

 

staticButton butnew(clientw/2,clienth/3+20);

staticButton butold(clientw/2,clienth/3+80);

staticButton butsel(clientw/2,clienth/3+140);

staticButton buthelp(clientw/2,clienth/3+200);

staticButton butquit(clientw/2,clienth/3+260);

 

staticSelBox sel(clientw/8+110,clienth*2/5+45,150,50);

staticRect selbkground(clientw/8,clienth*2/5,clientw/3,clienth/3);

staticButton butok(clientw/8+20,clienth*2/5+120,100,50);

staticButton butcl(clientw/8+145,clienth*2/5+120,100,50);

 

manager.Play(MID_MENUBKM);

 

if(firstrun)

{

          //设置动画

          menubk.SetAni(ANI_MENUBK);

          butnew.SetAni(ANI_BUTTON,ANI_BUTTON_NEW);

          butold.SetAni(ANI_BUTTON,ANI_BUTTON_OLD);

          butsel.SetAni(ANI_BUTTON,ANI_BUTTON_SEL);

          buthelp.SetAni(ANI_BUTTON,ANI_BUTTON_HELP);

          butquit.SetAni(ANI_BUTTON,ANI_BUTTON_QUIT);

 

          butok.SetAni(ANI_BUTTON,ANI_BUTTON_OK);

          butcl.SetAni(ANI_BUTTON,ANI_BUTTON_CANCEL);

          sel.Add(1).Add(2).Add(3).Add(4).Add(5).Add(6).Add(7).Add(8).Add(9);

          sel.SetAni(-1,ANI_BUTTON,ANI_BUTTON,-1,ANI_BUTTON_LEFT,ANI_BUTTON_RIGHT);

          selbkground.SetAni(ANI_SELBKGROUND);

}

 

//界面元素的响应

butnew.Deal();

butold.Deal();

butsel.Deal();

buthelp.Deal();

butquit.Deal();

//界面元素的绘制

menubk.Draw();

butnew.Draw();

butold.Draw();

butsel.Draw();

buthelp.Draw();

butquit.Draw();

 

//检测界面元素的状态

if(butnew.MousePressed())//新的开始

{

          level=1;

          butnew.Recover();

          state=GAME_CREATE;

}

if(butold.MousePressed())//旧的回忆

{

          ReadArchive();

          butold.Recover();

          state=GAME_RUN;

}

if(butsel.MousePressed())//选择关卡

{

          selbkground.Draw();

         sel.Deal();

          sel.Draw();

          butok.Deal();

          butcl.Deal();

 

          butok.Draw();

          butcl.Draw();

          if(butok.MousePressed())

          {

                    butsel.Recover();

                    butok.Recover();

                    level=atoi(sel.str().c_str());

                    state=GAME_CREATE;

          }

          if(butcl.MousePressed())

          {

                   butcl.Recover();

                    butsel.Recover();

          }

}

if(buthelp.MousePressed())//帮助

{

          buthelp.Recover();

          state=GAME_SHOWHELP;

}

if(butquit.MousePressed())

{

          ::PostQuitMessage(0);

}

firstrun=false;


}

 

voidGame::ShowLogo()

{

Rectanilog(400,450,350,100);

anilog.SetAni(ANI_LOGO);

anilog.Draw();

 

}

 

voidGame::ReadArchive()//读取存档

{

ifstream ifs("data\\archive.txt");

ifs>>level;

if(pPanel)deletepPanel;

if(level<=0)

{

          level=1;

          pPanel=newPanel(level);

}

else

{

          pPanel=newPanel(level);

          ifs>>*pPanel;

}

ifs.close();

manager.Play(MID_MAP0);

state=GAME_RUN;

roundtime=0;

}

 

voidGame::SaveArchive()//保存存档

{

ofstream ofs("data\\archive.txt");

if(!ofs)throwOuter_Error("打开存档文件失败!");

ofs<<level<<endl;

ofs<<*pPanel;

ofs.close();

}

 

 

//----------------------Manager----------------------------

Manager::~Manager()

{

for(PICPV::iteratorpit=pics.begin();pit<pics.end();pit++)

          delete*pit;

for(TILEPV::iteratortit=tiles.begin();tit<tiles.end();tit++)

          delete*tit;

for(ANIPV::iteratorait=anis.begin();ait<anis.end();ait++)

          delete*ait;

for(MIDPV::iteratormit=mids.begin();mit<mids.end();mit++)

          delete*mit;


}

 

voidManager::LoadRes()//加载资源

{

Add("data\\logo.bmp");

Add("data\\background.bmp");

Add("data\\fail.bmp");

Add("data\\win.bmp");//3

Add("data\\game.bmp");//4

Add("data\\ui.bmp");//5

Add("data\\outline.bmp");//6

Add("data\\help.bmp");//7


Add(0,0,0,800,600);//0 logo

Add(1,0,0,450,450);//1ground 

Add(1,450,0,450,450);//2ground 

Add(1,0,450,450,450);//3ground 

Add(1,450,450,450,450);//4ground 

 

Add(2,0,0,800,600);//5 failpic

 

Add(3,0,0,800,600);//6 winpic

 

Add(4,0,0,30,30);//7snake head

Add(4,30,0,30,30);//8snake body

Add(4,60,0,30,30);//9snake tail

Add(4,90,0,30,30);//10food

 

//ui

Add(5,0,0,200,50);//11new 

Add(5,0,50,200,50);//12 old

Add(5,0,100,200,50);//13 sel

Add(5,0,150,200,50);//14help

Add(5,0,200,200,50);//15quit

Add(5,0,250,200,50);//16 继续

Add(5,0,300,200,50);//17 返回

Add(6,0,0,800,600);//18outline

 

Add(5,200,0,50,50);//19selbox<

Add(5,250,0,50,50);//20selbox>

Add(5,300,0,350,250);//21selectlevel background

 

Add(5,0,350,100,50);//22 确定

Add(5,100,350,100,50);//23 取消

 

Add(7,0,0,800,600);//24 帮助

 

Add(5,0,400,100,50);//25 确定

Add(5,100,400,100,50);//26 取消

Add(5,200,50,50,50);//27 x按钮

 

Add(5,300,250,350,100);//logo28

 

vector<int>iv;

 

Add(0);//menubackground

Add(7);//snake1

Add(8);

Add(9);

Add(10);//food 4

//5 ground

Add(1);Add(2);Add(3);Add(4);

 

Add(5);//fail 9

 

Add(6);//win 10


//ui botton 11-15

Add(11);Add(12);Add(13);Add(14);Add(15);Add(16);Add(17);

//outline

Add(18);

Add(19);Add(20);//selbox<>

Add(21);//selectlevel background

Add(22);Add(23);//确定取消2223

 

Add(24);//帮助页面24

Add(25);Add(26);Add(27);//暂停返回X 25 26 27

Add(28);//logo28

}

 

voidManager::LoadMid()

{

AddMid("data\\menubkm.mid");

AddMid("data\\map0.mid");

}

 

Animation* Manager::PickAni(intp1,intp2,intp3)

{      //这个函数提供从标示符到动画指针的转换

switch(p1)

{

caseANI_LOGO:               returnanis[28];break;

caseANI_MENUBK:        returnanis[0];   break;

caseANI_SNAKE_HEAD:returnanis[1]; break;

caseANI_SNAKE_BODY:returnanis[2]; break;

caseANI_SNAKE_TAIL:returnanis[3];   break;

caseANI_FOOD:               returnanis[4];   break;

caseANI_BACKGROUND:

          switch(p2)

          {

          caseANI_BACKGROUND_GRASS:        returnanis[5];   break;

          caseANI_BACKGROUND_WOOD:         returnanis[6];   break;

          caseANI_BACKGROUND_ROCK: returnanis[7];   break;

          caseANI_BACKGROUND_TILE:   returnanis[8];   break;

          }

          returnanis[5];

          break;

caseANI_FAIL:       returnanis[9];   break;

caseANI_WIN:        returnanis[10];break;

caseANI_BUTTON:

          switch(p2)

          {

          caseANI_BUTTON_NEW:returnanis[11];break;

          caseANI_BUTTON_OLD:returnanis[12];break;

          caseANI_BUTTON_SEL:returnanis[13];break;

          caseANI_BUTTON_HELP:returnanis[14];break;

          caseANI_BUTTON_QUIT:returnanis[15];break;

          caseANI_BUTTON_CONTINUE:returnanis[16];break;

          caseANI_BUTTON_BACK:returnanis[17];break;

          caseANI_BUTTON_LEFT:returnanis[19];break;

          caseANI_BUTTON_RIGHT:returnanis[20];break;

          caseANI_BUTTON_OK:returnanis[22];break;

          caseANI_BUTTON_CANCEL:returnanis[23];break;

          caseANI_BUTTON_PAUSE:returnanis[25];break;

          caseANI_BUTTON_RECOVER:returnanis[26];break;

          caseANI_BUTTON_RETURN:returnanis[27];break;

          }

          break;

caseANI_OUTLINE:returnanis[18];break;

caseANI_SELBKGROUND:returnanis[21];break;

caseANI_HELP:returnanis[24];break;

}

returnNULL;

}

 

//以下是添加图元的函数

voidManager::Add(conststring& picfile)

{

pics.push_back(newPicture(picfile.c_str()));

}

 

voidManager::Add(Picture *ppic,intx,inty,intw,inth)

{

tiles.push_back(newTile(ppic,x,y,w,h));

}

 

voidManager::Add(intpicid,intx,inty,intw,inth)

{

tiles.push_back(newTile(pics.at(picid),x,y,w,h));       

}

 

voidManager::Add(constvector<int>&tilevct,intcycl,intinterval)

{

Animation* pani=newAnimation(cycl,interval);

anis.push_back(pani);

for(inti=0;i<(int)tilevct.size();i++)

          pani->AddTile(tiles.at(tilevct[i]));

}

 

voidManager::Add(intaniIndex)

{

Animation* pani=newAnimation(0,10);

anis.push_back(pani);

pani->AddTile(tiles.at(aniIndex));

}

 

//添加MID 背景音乐

voidManager::AddMid(conststring& midfile)

{

Mid* pmid=newMid(midfile);

mids.push_back(pmid);

}

 

Mid* Manager::PicMid(intid)

{

returnmids.at(id);

}

 

//播放背景音乐

voidManager::Play(intid)

{

if(curmid==id)return;

if(curmid!=-1)mids.at(curmid)->Stop();

mids.at(id)->Play();

curmid=id;

}

 

voidManager::Stop()

{

mids.at(curmid)->Stop();

curmid=-1;

}

 

Mid::Mid(conststring& fname):filename(fname)

{//mid的初始化

MCI_DGV_OPEN_PARMSmciOpen;

MCIERRORmciError;

mciOpen.lpstrDeviceType = "sequencer"; //设备名

mciOpen.lpstrElementName = (char*)filename.c_str();//设备元素

mciError=mciSendCommand(0,MCI_OPEN,MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,(DWORD)&mciOpen);

if(mciError)

{

          chars[80];

          mciGetErrorString(mciError,s,80);

          throwOuter_Error(s);

}

wDeviceID=mciOpen.wDeviceID; //保存设备ID

}

 

Mid::~Mid()

{

mciSendCommand(wDeviceID,MCI_CLOSE,0,NULL); 

}

 

voidMid::Play()

{

MCI_DGV_PLAY_PARMSmciPlay;

mciSendCommand(wDeviceID, MCI_SEEK, MCI_SEEK_TO_START,NULL); 

MCIERRORmciError=mciSendCommand(wDeviceID, MCI_PLAY, MCI_DGV_PLAY_REPEAT,(DWORD)&mciPlay);

if(mciError)

{

          chars[80];

          mciGetErrorString(mciError,s,80);

          throwOuter_Error(s);

}

}

 

voidMid::Stop()

{

mciSendCommand(wDeviceID,MCI_STOP,0,NULL); 

}

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

卷二:迷宫的设计及实现

 

 

一、    系统描述

规则:

迷宫为矩形区域,有一个入口一个出口,至少要有一条路径,并且要有多条死路。

需求分析:

程序实现迷宫的自动生成与自动寻路。迷宫的大小可以设定。程序能够将迷宫和路径画出

 

二、    功能模块结构

主要模块可以划分为:显示模块、迷宫生成模块、迷宫寻路模块。

模块

涉及的类或函数

功能

显示模块

InitInstance函数MyRegisterClass函数

WndProc函数

About函数

SetupDlg函数

实现界面的显示

迷宫生成模块

Panel类、Block类、NODE

迷宫的自动生成

迷宫寻路模块

Panel类、Block类、NODE

迷宫的自动寻路

 

显示模块:

先用MyRegisterClass函数注册窗口类,再用InitInstance创建并显示窗口。窗口完成后必须对其消息进行处理,WndProc即消息处理中心。

当用户单击菜单时,系统会调用WndProc函数,发送WM_COMMAND消息,由此,可以通过接受WM_COMMAND消息实现菜单响应。当窗口需要重画时,窗口会受到WM_PAINT消息,程序在此消息中响应的框架的绘制。

迷宫数据结构:

迷宫用一个Block类对象的矩阵表示,每个Block记录了右方和下方是否有墙,无墙代表连通,有墙代表阻隔。

迷宫生成思路:

首先令所有方块的墙全部关上,在面板中随机选取一个Block,随机选取一个移动方向,每移动一步就将响应的墙打开,并记录走过的位置。行走时随机选取方向,但不能走原来走过的位置,也不能超出面板。用栈来保存路径,每走一步就入栈,每退一步就出栈,遇到死路就出栈,直到最后栈空,所有的方块全部走完。

迷宫寻路思路:

迷宫的寻路方法与生成方法类似,也是用栈保存路径,走一步就入栈,退一步就出栈,遇到死路就退。从迷宫入口开始,遇到迷宫出口结束。

类视图:

 


三、    迷宫运行效果:

四、    总结:

 

在迷宫的设计编写过程中,我接触到了许多数据结构和算法方面的知识,例如栈、图等。起初的迷宫我采用的是递归算法,但是我发现递归算法有严重的弊端,当迷宫比较大的时候,递归会很快消耗完资源,从而终止运行。一开始我还以为是算法的问题,调试了很久才发现是资源耗尽了。否定的递归的方案之后,我试着用栈来实现,由于以前很少接触栈,我感到有些吃力,但是最后成功后再回头看栈,发现用栈来实现这类问题是多么简洁和高效。

除此之外,我认识到其实学习程序不应该过于关注语言细节,而应该注重数据结构和算法,注重解决问题的思路与方法。语言细节对于每一门语言都不相同,但是解决问题的方法却是通用的。我们应该学会怎样去提出问题、分析问题、解决问题,而不是将程序的语言作为清规戒律。在制作迷宫的过程中,我提出过很多方案,许多都是中途发现不能再继续下去,但在不懈的努力下,终于实现的预期要求。我想说的是,我们既要勇于探索不怕困难,又要充分考虑方案的可行性。

 

 

五、    参考文献:

 

TheC++ Programming Language——()Bjarne Stroustrup

Windows程序设计——CharlesPetzold

 

六、    附录:

 

程序清单:

//迷宫.cpp 

//

#include<windows.h>

#include<stdlib.h>

#include<malloc.h>

#include<memory.h>

#include<tchar.h>

#include"resource.h"

#include"maze.h"

 

#defineMAX_LOADSTRING 100

 

//Global Variables:

HINSTANCE hInst;                                                                   //current instance

TCHAR szTitle[MAX_LOADSTRING];                                                                      //The title bar text

TCHAR szWindowClass[MAX_LOADSTRING];                                                                        //The title bar text

 

intNUM_X=50;

intNUM_Y=50;

 

Panel *panel;

 

//Foward declarations of functions included in this code module:

ATOM                                   MyRegisterClass(HINSTANCE hInstance);

BOOL                                    InitInstance(HINSTANCE, int);

LRESULTCALLBACK    WndProc(HWND,UINT, WPARAM, LPARAM);

LRESULTCALLBACK    About(HWND,UINT, WPARAM, LPARAM);

LRESULTCALLBACK    SetupDlg(HWND,UINT, WPARAM, LPARAM);

 

intAPIENTRY WinMain(HINSTANCEhInstance,

                     HINSTANCEhPrevInstance,

                     LPSTR     lpCmdLine,

                     int       nCmdShow)

{

         //TODO: Place code here.

MSG msg;

HACCELhAccelTable;

 

// Initialize global strings

LoadString(hInstance,IDS_APP_TITLE, szTitle, MAX_LOADSTRING);

LoadString(hInstance,IDC_MY, szWindowClass, MAX_LOADSTRING);

MyRegisterClass(hInstance);

 

panel=newPanel(NUM_X,NUM_Y);

panel->Generate();

// Perform applicationinitialization:

if(!InitInstance (hInstance, nCmdShow))

{

          returnFALSE;

}

 

hAccelTable = LoadAccelerators(hInstance,(LPCTSTR)IDC_MY);

 

// Main message loop:

while (GetMessage(&msg, NULL, 0, 0))

{

          if(!TranslateAccelerator(msg.hwnd,hAccelTable, &msg)) 

          {

                    TranslateMessage(&msg);

                    DispatchMessage(&msg);

          }

}

 

delete panel;

returnmsg.wParam;

}

 

//注册窗口类

ATOM MyRegisterClass(HINSTANCEhInstance)

{

WNDCLASSEX wcex;

 

wcex.cbSize = sizeof(WNDCLASSEX); 

 

wcex.style                            =CS_HREDRAW | CS_VREDRAW;

wcex.lpfnWndProc   = (WNDPROC)WndProc;

wcex.cbClsExtra                =0;

wcex.cbWndExtra             =0;

wcex.hInstance                  =hInstance;

wcex.hIcon                          =LoadIcon(hInstance, (LPCTSTR)IDI_MY);

wcex.hCursor             =LoadCursor(NULL, IDC_ARROW);

wcex.hbrBackground        = (HBRUSH)(COLOR_WINDOW+1);

wcex.lpszMenuName        = (LPCSTR)IDC_MY;

wcex.lpszClassName         = szWindowClass;

wcex.hIconSm          =LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

 

returnRegisterClassEx(&wcex);

}

 

BOOL InitInstance(HINSTANCEhInstance,intnCmdShow)

{//创建显示窗口

   HWNDhWnd;

 

   hInst = hInstance;//Store instance handle in our global variable

 

   hWnd = CreateWindowEx(NULL,szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

      CW_USEDEFAULT,CW_USEDEFAULT, 800, 600, NULL,NULL, hInstance, NULL);

 

   if (!hWnd)

   {

      returnFALSE;

   }

 

   ShowWindow(hWnd, nCmdShow);

   UpdateWindow(hWnd);

 

   returnTRUE;

}

 

//处理消息

LRESULTCALLBACKWndProc(HWNDhWnd,UINTmessage, WPARAMwParam, LPARAMlParam)

{

int wmId,wmEvent;

PAINTSTRUCT ps;

HDC hdc;

 

charinfostr[100];

int width;

int height;

 

switch (message)

{

          caseWM_COMMAND://菜单消息

                    wmId    = LOWORD(wParam);

                    wmEvent = HIWORD(wParam); 

                    // Parsethe menu selections:

                    switch(wmId)

                    {

                             caseIDM_ABOUT: //关于菜单

                                DialogBox(hInst,(LPCTSTR)IDD_ABOUTBOX, hWnd,(DLGPROC)About);

                                break;

                             caseIDM_SETUP: //设置菜单

                                      DialogBox(hInst,(LPCTSTR)IDD_SETUP,hWnd,(DLGPROC)SetupDlg);

                                      InvalidateRect(hWnd,NULL,true);

 

                                      break;

                             caseIDM_EXIT: //退出菜单

                                DestroyWindow(hWnd);

                                break;

                             caseID_MAZE_GENERATE: //生成迷宫菜单

                                      panel->Generate();

                                      InvalidateRect(hWnd,NULL,true);

                                      break;

                             caseIDM_FINDPATH: //迷宫寻路菜单

                                      panel->FindPath();

                                      InvalidateRect(hWnd,NULL,true);

                                      break;

                             default:

                                returnDefWindowProc(hWnd, message,wParam,lParam);

                    }

                    break;

          caseWM_PAINT: //绘图消息

                    hdc = BeginPaint(hWnd,&ps);

                    // TODO:Add any drawing code here...

                    RECTrt;

                    GetClientRect(hWnd,&rt);

 

                    height=rt.bottom-rt.top-30;

                    width=height;

                    //绘制信息

                    sprintf(infostr,"宽度:%d",NUM_X);

                    TextOut(hdc,rt.left+height+40,rt.top+10,infostr,strlen(infostr));


                    sprintf(infostr,"高度:%d",NUM_Y);

                    TextOut(hdc,rt.left+height+40,rt.top+40,infostr,strlen(infostr));

 

                    panel->SetDC(hdc);

                    panel->Draw(rt.left+10,rt.top+10,width,height);

                    

                    EndPaint(hWnd,&ps);

                    break;

          caseWM_DESTROY:

                    PostQuitMessage(0);

                    break;

          default:

                    returnDefWindowProc(hWnd, message,wParam,lParam);

   }

   return 0;

}

 

//关于对话框消息处理

LRESULTCALLBACK About(HWNDhDlg, UINTmessage, WPARAMwParam, LPARAMlParam)

{

switch (message)

{

          caseWM_INITDIALOG:

                             returnTRUE;

 

          caseWM_COMMAND:

                    if(LOWORD(wParam) == IDOK || LOWORD(wParam)== IDCANCEL) 

                    {

                             EndDialog(hDlg,LOWORD(wParam));

                             returnTRUE;

                    }

                    break;

}

    returnFALSE;

}

 

//设置对话框消息处理

LRESULTCALLBACKSetupDlg(HWNDhDlg,UINTmessage, WPARAMwParam, LPARAMlParam)

{

int ex,ey;

int wmId,wmEvent;

switch (message)

{

          caseWM_INITDIALOG:

                    SetDlgItemInt(hDlg,IDC_EDIT_X,NUM_X,TRUE);

                    SetDlgItemInt(hDlg,IDC_EDIT_Y,NUM_Y,TRUE);

                    returnTRUE;

 

          caseWM_COMMAND:

                    wmId    = LOWORD(wParam);

                    wmEvent = HIWORD(wParam); 

                    switch(wmId)

                    {

                    caseIDOK:

                             ex=GetDlgItemInt(hDlg,IDC_EDIT_X,NULL,TRUE);

                             ey=GetDlgItemInt(hDlg,IDC_EDIT_Y,NULL,TRUE);

                             if(ex<2||ex>500||ey<2||ey>500)

                             {

                                      MessageBox(hDlg,"输入数据有误!","提示",MB_OK);

                                      break;

                             }

                             NUM_X=ex;

                             NUM_Y=ey;

                             deletepanel;

                             panel=newPanel(NUM_X,NUM_Y);

                             panel->Generate();                      

                    caseIDCANCEL:

                             EndDialog(hDlg,wmId);

                             returnTRUE;

                    }

                    break;

}

    returnFALSE;

}

 

 

 

 

//*********************maze.h***********************

 

#include<windows.h>

#include<stack>

#include<vector>

usingstd::stack;

usingstd::vector;

 

enumDIRECTION{RIGHT=0,BOTTOM=1,LEFT=2,TOP=3};

 

classBlock                  //方块类,把迷宫面板分为许多小方块后,每个方块的类

{

boolrightwall;

boolbottomwall;

Block*neighbour[4];

long flag;

 

public:

staticHDC pDC;

 

Block():rightwall(true),bottomwall(true)

          {};

void Init(Block* rightneb,Block* bottomneb,Block* leftneb,Block* topneb)

{

          neighbour[RIGHT]=rightneb;   neighbour[BOTTOM]=bottomneb;

          neighbour[LEFT]      =leftneb;  neighbour[TOP]         =topneb;

}

//设置墙

voidSetWall(boolrwall=true,boolbwall=true)

          {rightwall=rwall;bottomwall=bwall;}

voidSetWall(int direction,boolwall=true);

voidSetRWall(boolrwall=true){rightwall=rwall;}

voidSetBWall(boolbwall=true){bottomwall=bwall;}

//是否有墙

bool rw()const{returnrightwall;}

bool bw()const{returnbottomwall;}

bool lw()const{returnneighbour[LEFT]?neighbour[LEFT]->rw():true;}

bool tw()const{returnneighbour[TOP]?neighbour[TOP]->bw():true;}

//获取下一个方块

Block* Neb(intdirection){returnneighbour[direction];};

boolBlock::wall(intdirection);

bool OnWall(intdirection)         const{returnneighbour[direction]==NULL?true:false;}

voidRandSet(){rightwall=rand()%2==0?false:true;bottomwall=rand()%2==0?false:true;}

//设置标志

bool Flag(intbit=0)const{returnflag&(1<<bit)?true:false;}

voidSetFlag(intbit=0,boolflg=true)

{

          if(flg)flag|=(1<<bit);

          elseflag&= ~(1<<bit);

}

void ClearFlag(){flag=0;}

int GoNext(intnoflg=0);//走到下一个方块

intFindNext(int noflg=1);//寻下一个路

void Draw(intx,int y,intw,int h);

};

 

classNODE//用来表示方块的x、y坐标

{

int x,y;

public:

NODE(){}

NODE(intvx,intvy):x(vx),y(vy){}

int GetX()const{returnx;}

int GetY()const{returny;}

void Set(intvx,intvy){x=vx;y=vy;}

};

 

classPanel//面板类,对整个迷宫操作

{

intxnum,ynum;

Block**blocks;

HDC pDC;

voidClearFlag(int bit);

voidClearFlag();

 

vector<NODE> path;

public:

voidFindPath();        //寻路

 

Panel(int nx,intny);

~Panel();

voidGenerate();        //生成迷宫

void Draw(intx,int y,intw,int h);

void SetDC(HDChdc){pDC=hdc;}

 


};

 

 

 

 

//****************maze.cpp**************************

 

#include"maze.h"

#include<stack>

#include<vector>

usingstd::stack;

usingstd::vector;

 

HDCBlock::pDC=NULL;

 

voidBlock::Draw(intx,inty,intw,inth)

{

if(!OnWall(RIGHT)&&rw())

{

          MoveToEx(pDC,x+w,y,NULL);

          LineTo(pDC,x+w,y+h);

}

if(!OnWall(BOTTOM)&&bw())

{

          MoveToEx(pDC,x,y+h,NULL);

          LineTo(pDC,x+w,y+h);

}

}

 

voidBlock::SetWall(intdirection,boolwall)

{//通过方向形参设置墙的有无

switch(direction)

{

caseRIGHT:

          rightwall=wall;

          break;

caseBOTTOM:

          bottomwall=wall;

          break;

caseLEFT:

          if(neighbour[LEFT])neighbour[LEFT]->SetRWall(wall);

          break;

caseTOP:

          if(neighbour[TOP])neighbour[TOP]->SetBWall(wall);

          break;

}

}

 

boolBlock::wall(intdirection)

{//通过方向形参判断该方向是否有墙

switch(direction)

{

caseRIGHT:return rw();break;

caseBOTTOM:return bw();break;

caseLEFT:return lw();break;

caseTOP:return tw();break;

}

returntrue;

}

 

 

intBlock::GoNext(intnoflg)

{//生成迷宫时走到下一步

vector<int>nxtblk; 

for(inti=0;i<4;i++)

          if(neighbour[i]&&!neighbour[i]->Flag(noflg))

                    nxtblk.push_back(i);

if(nxtblk.size()<=0)return-1;

intsel=nxtblk[rand()%nxtblk.size()];

return sel;

}

 

intBlock::FindNext(intnoflg)

{//寻路时走到下一步

SetFlag(noflg);

for(inti=0;i<4;i++)

          if(!wall(i)&&!neighbour[i]->Flag(noflg))

                    returni;

return -1;

}

 

Panel::Panel(intnx,intny)

          :xnum(nx),ynum(ny)

{//生成方块二维数组

blocks=newBlock*[ynum];

for(inti=0;i<ynum;i++)

          blocks[i]=newBlock[xnum];

 

for(intiy=0;iy<ynum;iy++)

          for(intix=0;ix<xnum;ix++)

                    blocks[iy][ix].Init(ix<xnum-1?&blocks[iy][ix+1]:NULL,

                                                                  iy<ynum-1?&blocks[iy+1][ix]:NULL,

                                                                  ix>0?&blocks[iy][ix-1]:NULL,

                                                                  iy>0?&blocks[iy-1][ix]:NULL);

ClearFlag();

 

}

 

Panel::~Panel()

{

for(inti=0;i<ynum;i++)

          delete[]blocks[i];      

}

 

voidPanel::Generate()//生成迷宫

{

stack<Block*> bs;

 

for(intiy=0;iy<ynum;iy++)

          for(intix=0;ix<xnum;ix++)

                    blocks[iy][ix].SetWall();

ClearFlag(0);

 

intfstx=rand()%xnum;

intfsty=rand()%ynum;

blocks[fsty][fstx].SetFlag();

bs.push(&blocks[fsty][fstx]);

while(!bs.empty())

{

          Block*curblk=bs.top();

          intnxtdrt=curblk->GoNext();

          

          if(nxtdrt!=-1)

          {

                    curblk->SetWall(nxtdrt,false);

                    curblk->Neb(nxtdrt)->SetFlag(0);

                    curblk=curblk->Neb(nxtdrt);

                    bs.push(curblk);//走一步就入栈

          }

          else

          {//死路出栈

                    bs.pop();

          }

}       

 

while(!path.empty())

          path.pop_back();

ClearFlag(1);


}

 

voidPanel::Draw(intx,inty,intw,inth)

{

//绘制迷宫和路径

HPENhp=CreatePen(PS_SOLID,1,RGB(0,0,0));

SelectObject(pDC,hp);

 

int blkw=w/xnum;

int blkh=h/ynum;

//draw frame

Rectangle(pDC,x,y,x+blkw*xnum,y+blkh*ynum);

 

HBRUSHbrush=CreateSolidBrush(RGB(255,0,0));

SelectObject(pDC,brush);

Ellipse(pDC,x,y,x+blkw,y+blkh);

Ellipse(pDC,x+blkw*(xnum-1),y+blkh*(ynum-1),x+blkw*xnum,y+blkh*ynum);

//draw block

Block::pDC=pDC;

for(intiy=0;iy<ynum;iy++)

          for(intix=0;ix<xnum;ix++)

                    blocks[iy][ix].Draw(x+blkw*ix,y+blkh*iy,blkw,blkh);

 

HPENpathpen=CreatePen(PS_SOLID,xnum>=100?1:2,RGB(255,0,0));

SelectObject(pDC,pathpen);

//draw path

for(inti=0;i<path.size();i++)

{

          intcx=x+blkw*(path[i].GetX()+0.5);

          intcy=y+blkh*(path[i].GetY()+0.5);

          if(i==0)MoveToEx(pDC,cx,cy,NULL);

          elseLineTo(pDC,cx,cy);

}

 

DeleteObject(brush);

DeleteObject(pathpen);

DeleteObject(hp);

}

 

voidPanel::ClearFlag(intbit)

{

for(intiy=0;iy<ynum;iy++)

          for(intix=0;ix<xnum;ix++)

                    blocks[iy][ix].SetFlag(bit,false);

}

 

voidPanel::ClearFlag()

{

for(intiy=0;iy<ynum;iy++)

          for(intix=0;ix<xnum;ix++)

                    blocks[iy][ix].ClearFlag();

}

 

voidPanel::FindPath()

{//寻路

int x,y;

x=0;y=0;


while(!path.empty())

          path.pop_back();

ClearFlag(1);

 

path.push_back(NODE(0,0));

 

while(!path.empty())

{

          NODEnode=path.back();

          x=node.GetX();

          y=node.GetY();

          intdrt=blocks[y][x].FindNext();

          switch(drt)

          {

          caseRIGHT:x++;break;

          caseBOTTOM:y++;break;

          caseLEFT:x--;break;

          caseTOP:y--;break;

          }

          if(drt==-1)path.pop_back();

          elsepath.push_back(NODE(x,y));

          if(x==xnum-1&&y==ynum-1)

                    break;

}

 

}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值