Visual C++游戏编程基础之搜寻迷宫出口

一、基本思路

1.建立8*8迷宫数组,使用0,1,2,3初始化,0,1,2,3分别表示墙、通道、入口、出口,使用地图贴图知识建立迷宫;

2.建立堆栈结构记录走过的方格编号,即走到某个方格就把该方格编号压入堆栈;若发现路不通,就把该编号出栈,栈顶元素表示

   小球所在的方格编号;

3.根据迷宫数组中的值,在初始化函数中对每一格进行贴图,墙贴蓝色的,其余均为白色,找到迷宫入口,记录编号并压入堆栈,

   record数组记录走过的棋格,将该编号对应的方格设为0;

4.到了MyPaint函数,根据编号确定小球的贴图坐标,把小球贴到对应方格;

5.根据小球编号判断其上、下、左、右是否能走,假设下能走,那就把下对应的编号压入堆栈,更新record及Nowpos和Prepos;

6.如果发现到了某一格走不动了,就退回到上一格,更新Nowpos和Prepos;

二、效果

三、代码如下


#include "stdafx.h"
#include <stack>
using namespace std;

const int rows = 8,cols = 8;

HINSTANCE hInst;
HBITMAP ball;
HDC		hdc,mdc,bufdc;
HWND	hWnd;
DWORD	tPre,tNow;
char	*str;//记录目前搜寻状态的字符串指针
int		nowPos,prePos;//nowPos--小球目前位置的方格编号,小球贴图;prePos--小球之前位置的方格编号,以此编号白色覆盖小球贴图
bool	find;//是否找到迷宫出口
stack<int> path;//建立int型堆栈path
//0,1,2,3代表墙、通道、入口和出口
int mapIndex[rows*cols] = { 0,2,0,0,0,0,0,0,   //材1
							0,1,0,1,1,1,1,0,   //材2
							0,1,0,1,0,1,1,0,   //材3
							0,1,0,0,0,1,1,0,   //材4
							0,1,1,1,1,1,1,0,   //材5
							0,1,0,0,0,0,1,0,   //材6
							0,0,1,1,1,1,1,0,   //材7
							0,0,0,0,0,0,3,0 }; //材8
int record[rows*cols];//标记不可通过的方格(墙)及走过的方格

ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
void				MyPaint(HDC hdc);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	MSG msg;

	MyRegisterClass(hInstance);

	if (!InitInstance (hInstance, nCmdShow)) 
	{
		return FALSE;
	}

    while( msg.message!=WM_QUIT )
    {
        if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
		else
		{
			tNow = GetTickCount();
			if(tNow-tPre >= 100)
				MyPaint(hdc);
		}
    }
	
	return msg.wParam;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
	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			= NULL;
	wcex.hCursor		= NULL;
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= NULL;
	wcex.lpszClassName	= "canvas";
	wcex.hIconSm		= NULL;

	return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	HBITMAP bmp;
	hInst = hInstance;

	hWnd = CreateWindow("canvas", "绘图窗口" , WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

	if (!hWnd)
	{
		return FALSE;
	}

	MoveWindow(hWnd,200,100,430,450,true);
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);
	
	hdc = GetDC(hWnd);
	mdc = CreateCompatibleDC(hdc);
	bufdc = CreateCompatibleDC(hdc);

	bmp = CreateCompatibleBitmap(hdc,cols*50,rows*50);
	SelectObject(mdc,bmp);

	HBITMAP tile;
	int rowNum,colNum;
	int i,x,y;

	tile = (HBITMAP)LoadImage(NULL,"tile.bmp",IMAGE_BITMAP,50,50,LR_LOADFROMFILE);//加载迷宫背景图
	ball = (HBITMAP)LoadImage(NULL,"ball.bmp",IMAGE_BITMAP,50,50,LR_LOADFROMFILE);//加载小球图

	//按照“mapIndex”数组中的定义进行地图拼接 
	for (i=0;i<rows*cols;i++)
	{
		record[i] = mapIndex[i];

		rowNum = i / cols;			//求列编号
		colNum = i % cols;			//求行编号
		x = colNum * 50;			//贴图X的坐标
		y = rowNum * 50;			//贴图Y的坐标
		
		SelectObject(bufdc,tile);//把墙背景图存到bufdc

		if(!mapIndex[i])//遇到墙贴蓝色背景图
			BitBlt(mdc,x,y,50,50,bufdc,0,0,SRCCOPY);
		else
		{
			if(mapIndex[i] == 2)	//find迷宫入口
			{
				nowPos = i;//把球的当前位置设为该元素值所代表的迷宫方格
				path.push(i);//把该元素编号压入堆栈
				record[i] = 0;//表示该编号对应的方格已走过
			}
			BitBlt(mdc,x,y,50,50,bufdc,0,0,WHITENESS);//该元素对应的方格设为白色
		}
	}
	prePos = cols * rows + 1;//第一次在窗口外;之后画面更新后再记录小球前一次贴图位置

	MyPaint(hdc);

	return TRUE;
}

void MyPaint(HDC hdc)
{
	int rowNum,colNum;//列编号和行编号
	int x,y;//贴图坐标
	int up,down,left,right;

	//清除上次贴图
	rowNum = prePos / cols;//列编号
	colNum = prePos % cols;//行编号
	x = colNum * 50;
	y = rowNum * 50;

	SelectObject(bufdc,ball);
	BitBlt(mdc,x,y,50,50,bufdc,0,0,	WHITENESS);

	//小球贴图
	rowNum = nowPos / cols;
	colNum = nowPos % cols;
	x = colNum * 50;
	y = rowNum * 50;

	SelectObject(bufdc,ball);
	BitBlt(mdc,x,y,50,50,bufdc,0,0,	SRCCOPY);

	if(!find)
	{
		str = "找寻出口中......";

		up    = nowPos - cols;//小球所在位置上方编号为'Up'的方格
		down  = nowPos + cols;//小球所在位置下方编号为'Down'的索引值
		left  = nowPos - 1;
		right = nowPos + 1;

		if(up>=0 && record[up])						//Up要大于等于数组的最小索引值0(第一个数)
		{
			path.push(up);
			record[up] = 0;
			prePos = nowPos;
			nowPos = up;//球到了上面去

			if(mapIndex[nowPos] == 3)				//判断是不是出口
				find = true;
		}
		else if(down<=cols*rows-1 && record[down])  //down要小于等于数组最大索引值
		{
			path.push(down);
			record[down] = 0;
			prePos = nowPos;
			nowPos = down;

			if(mapIndex[nowPos] == 3)
				find = true;
		}
		else if(left>=rowNum*cols&& record[left])  //小球所在列的最小索引值,第0列就是0号;第1列就是8号
		{
			path.push(left);
			record[left] = 0;
			prePos = nowPos;
			nowPos = left;

			if(mapIndex[nowPos] == 3)
				find = true;
		}
		else if(right<=(rowNum+1)*cols-1 && record[right])  //小球所在列的最大索引值,第0列就是7号;第1列就是15号
		{
			path.push(right);
			record[right] = 0;
			prePos = nowPos;
			nowPos = right;

			if(mapIndex[nowPos] == 3)
				find = true;
		}
		else					
		{
			if(path.size() <= 1)//经过一番探索之后,反复的入栈出栈,最后退回到起点	
				str = "迷宫无出口...";
			else
			{
				path.pop();//path.size>1,则退回到之前的方格
				prePos = nowPos;
				nowPos = path.top();//重设当前位置
			}
		}
	}
	else
	{
		str = "找到迷宫出口!";
	}

	TextOut(mdc,0,0,str,strlen(str));
	BitBlt(hdc,10,10,cols*50,rows*50,mdc,0,0,SRCCOPY);

	tPre = GetTickCount();
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
		case WM_KEYDOWN:				
			if(wParam==VK_ESCAPE)		
				PostQuitMessage(0);
			break;
		case WM_DESTROY:					
			DeleteDC(mdc);
			DeleteDC(bufdc);
			DeleteObject(ball);

			ReleaseDC(hWnd,hdc);

			PostQuitMessage(0);
			break;
		default:							
			return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

猜你喜欢

转载自blog.csdn.net/Sruggle/article/details/92429105
今日推荐