這是大二上學期做的一個小玩意兒,上傳上來湊個數哈哈哈。
首先貼出下載鏈接:
1. 完整Qt源碼:http://download.csdn.net/detail/mahabharata_/9824044
2. 發佈的可執行程序:http://download.csdn.net/detail/mahabharata_/9824066
程序截圖:
1. 動畫演示自動尋路的過程(使用QSequentialAnimation)
2. 生成的一個較大迷宮和打印路徑。
最近,我陸續地把以前做的一些Qt或OpenGL的小程序、遊戲等整理出來。其中的這個迷宮遊戲,是我在大二時期爲《數據結構綜合實習》所做的程序。
當時倒是覺得寫完這個程序對我的Qt技巧的提升還挺大的。雖然現在時隔了將近2年,回頭重新審視這段代碼,發現不管是以前的代碼結構,還是Qt的熟練程度還是差了一些火候。
不過這裏還是整理分享出來,希望能給那些希望學好Qt的同學一些幫助。順帶着,也可以通過這個程序,瞭解一下迷宮的隨機生成算法、DFS的尋路算法。
說明:
1. 這個程序的靈感來自於最近流行的平面像素風格RPG遊戲。
2. 當進入程序時,先點擊“生成迷宮”,程序會自動生成一個給定寬度、高度的隨機迷宮。
3. 點擊“玩家模式”按鈕,可以像普通RPG遊戲那樣,WASD操縱小人的移動,中間使用的插值會使小人的運動顯得比較連貫。
4. 點擊“圓形按鈕”,小人將會動畫演示自動尋路的過程。
5. 點擊“繪製路徑”按鈕,將會在地圖上打印小人的路徑。
核心算法:
0. 基本的數據結構
class point
{
public:
int i;
int j;
int state;
point();
point(int i,int j, int state);
bool operator==(const point& maze);
};
class Maze
{
private:
point **recordMatrix;
QStack<point> *MazeStack;
point move[4]; //人移動的四個方向
public:
point **matrix;
int height;//迷宮矩陣的行
int width;//迷宮矩陣的列
int X;//人的位置
int Y;
QList<point> pathStack; // 存儲動畫演示的中間過程。
QList<point> autoPath; //存放最終的路徑。
Maze();
void initMaze(int h,int w);
void createMaze();
void autoFindPath();
private:
void setDirFalse(bool& up,bool& down,bool& right,bool& left);
};
1. 迷宮的隨機生成:
在隨機生成的迷宮中要求任意兩點,都可以找到一條路徑相通,所以在圖論中可以認爲迷宮就是一個連通圖。產生連通圖的常見方法有kruskal和prim算法,一般來講使用prim算法產生的迷宮比較自然和隨機。其實本質是,一個有約束條件的深搜。
void Maze::createMaze()
{
int i=3,j=3;
matrix[i][j].state=1;
point temp;
temp.i=i;
temp.j=j;
temp.state=1;
bool up=false, down=false, right=false, left=false;
while(true)
{
temp.i=i;
temp.j=j;
int randNum=qrand()%4;
switch(randNum)
{
case 0://上
if(!up&&i>2&&matrix[i-2][j].state==0)
{
MazeStack->push(temp);
matrix[i-2][j].state=1;
matrix[i-1][j].state=1;
i=i-2;
setDirFalse(up, down, right, left);
}
else
up=true;
break;
case 1://下
if(!down&&i<height-3&&matrix[i+2][j].state==0)
{
MazeStack->push(temp);
matrix[i+2][j].state=1;
matrix[i+1][j].state=1;
i=i+2;
setDirFalse(up, down, right, left);
}
else
down=true;
break;
case 2://左
if(!left&&j>2&&matrix[i][j-2].state==0)
{
MazeStack->push(temp);
matrix[i][j-2].state=1;
matrix[i][j-1].state=1;
j=j-2;
setDirFalse(up, down, right, left);
}
else
left=true;
break;
case 3://右
if(!right&&j<width-3&&matrix[i][j+2].state==0)
{
MazeStack->push(temp);
matrix[i][j+2].state=1;
matrix[i][j+1].state=1;
j=j+2;
setDirFalse(up, down, right, left);
}
else
right=true;
break;
}
if(up&&down&&right&&left)//如果當前訪問節點四個方向都沒有可拆的節點,回溯
{
if(!MazeStack->empty())
{
i=MazeStack->top().i;
j=MazeStack->top().j;
MazeStack->pop();
setDirFalse(up, down, right, left);
}
else//如果棧爲空的話就返回,此時迷宮矩陣已經創建完畢
{
return;
}
}
}
}
2. 迷宮的自動尋路:
void Maze::autoFindPath()
{
pathStack.clear();
recordMatrix[X][Y].state = 0; //出口位置標記爲已經訪問過,0爲牆
point temp(X,Y,0);
pathStack.push_back(temp);
int i , j , d ;
while(!pathStack.isEmpty())
{
point top = pathStack.back();
pathStack.pop_back();
if(!autoPath.isEmpty()&& !(top==autoPath.back()))
autoPath.push_back(top);
if(autoPath.isEmpty())
autoPath.push_back(top);
i = top.i;j=top.j;d=top.state;
while(d < 4)
{
temp.i = i+move[d].i;
temp.j = j+move[d].j;
if(temp.i == height-2 &&temp.j ==width-2)
{
pathStack.push_back(top);
pathStack.push_back(temp);
autoPath.push_back(temp);
for(int i=0 ; i<pathStack.size();i++)
{
qDebug()<<"("<<pathStack[i].i<<","<<pathStack[i].j<<")";
}
return;
}
if(matrix[temp.i][temp.j].state == 1 && recordMatrix[temp.i][temp.j].state == 1)
{
recordMatrix[temp.i][temp.j].state = 0;
top.state=d;
pathStack.push_back(top);
temp.state=0;
pathStack.push_back(temp);
autoPath.push_back(temp);
break;
}
d++;
}
if(d==4)
autoPath.push_back(pathStack.back());
}
}