mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QPushButton>
#include "mazewidget.h"
class MainWindow : public QWidget
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
signals:
public slots:
void changeWin();
private:
QPushButton b;
MazeWidget sub;
protected:
void paintEvent(QPaintEvent*);
};
#endif // MAINWINDOW_H
mazewidget.h
#ifndef MAZEWIDGET_H
#define MAZEWIDGET_H
#include <QWidget>
#include <iostream>
#include <vector>
#include <queue>
#include <QTime>
#include <QLineEdit>
#include <QPushButton>
#include <QPainter>
#include <QLabel>
#include <QMessageBox>
#include <QDebug>
#include <QKeyEvent>
#include <QPixmap>
#include <QPen>
#include <QStack>
using namespace std;
namespace Ui
{
class MazeWidget;
}
class Maze //存放迷宫节点
{
public:
int i,j; //迷宫节点的坐标
int state; //迷宫节点的状态,其中:0:墙;1:路:2:自动寻路路径
};
class Box1 //存放自动寻路时路径的信息
{
public:
int i,j;
int pre; //前驱节点编号
int num; //当前节点编号
};
class MazeWidget : public QWidget
{
Q_OBJECT
public:
explicit MazeWidget(QWidget *parent = 0);
~MazeWidget();
void paintEvent(QPaintEvent *); //绘图事件
void CreatMaze(); //创建迷宫
void keyPressEvent(QKeyEvent*); //键盘事件
void FindShortWay(); //自动寻路
void timerEvent(QTimerEvent*); //定时器事件
int score=0;
private:
Ui::MazeWidget *ui;
Maze **map; //二维数组,存放迷宫地图
vector<Maze> FinalPath; //存放自动寻路的路径
QStack<Maze> MazeStack; //存放迷宫节点
QStack<Box1> Box1Stack; //存放自动寻路中处理后的节点
queue<Box1> Box1Queue; //存放自动寻路中未处理的节点
int M,N; //迷宫的行列数
bool paint_flag; //判断是否需要绘制画面
QLineEdit *Xline; //行编辑控件
QLineEdit *Yline; //列编辑控件
QLabel *tips; //显示提示的标签
QLabel *recounts; //显示“倒计时”图片的标签
QPushButton *creatmazebtn; //创建迷宫的按钮
QPushButton *findshortwaybtn; //自动寻路的按钮
QLabel *time; //显示时间的标签
QLabel *toScore; //显示得分的标签
int X,Y; //玩家的坐标
int timerId; //定时器ID
bool find=false; //判断自动寻路是否到达终点
bool flag=false; //判断有没有通路
bool useFindRoad=false; //判断游戏中是否使用了自动寻路功能
private slots:
void creatmazebtnSlot();
void findshortwaybtnSlot();
void counttimeSlot();
};
#endif // MAZEWIDGET_H
main.cpp
#include "mazewidget.h"
#include"mainwindow.h"
#include <QApplication>
#include<QtMultimedia/QMediaPlayer>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include <QPainter>
#include <QSound>
MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
this->setWindowTitle("开始界面");
b.setParent(this);
b.setGeometry(250,200,400,150);
b.setStyleSheet("QPushButton{border-image:url(:/maze/image/start.png);border-radius:5px;}");
QSound *sound=new QSound(":/maze/image/bgm.wav",this);
sound->setLoops(-1);
sound->play();
this->setFixedSize(900,600);
connect(&b,&QPushButton::released,this,&MainWindow::changeWin);
}
void MainWindow::changeWin() //改变窗口
{
sub.show();
this->hide();
}
void MainWindow::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.drawPixmap(0,0,width(),height(),QPixmap(":/maze/image/background.png"));
}
mazewidget.cpp
#include "mazewidget.h"
#include "ui_mazewidget.h"
#include <QSound>
MazeWidget::MazeWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MazeWidget)
{
ui->setupUi(this);
paint_flag=false;
M=35;
N=35;
X=3;
Y=3;
this->setWindowTitle("迷宫");
this->setFixedSize((N+10)*20,(M+1)*20);
this->setFocus(Qt::MouseFocusReason);
Xline=new QLineEdit(this);
Yline=new QLineEdit(this);
Xline->setText("35");
Yline->setText("35");
Xline->setGeometry((N+2)*20+10,245,40,20);
Yline->setGeometry((N+2)*20+70,245,40,20);
creatmazebtn=new QPushButton(this);
creatmazebtn->setText("开始游戏");
creatmazebtn->setGeometry((N+2)*20,280,120,30);
creatmazebtn->setStyleSheet("QPushButton{background-color:yellow;}");
findshortwaybtn=new QPushButton(this);
findshortwaybtn->setText("自动寻路");
findshortwaybtn->setStyleSheet("QPushButton{background-color:rgb(250,128,114);}");
findshortwaybtn->setGeometry((N+2)*20,20,120,30);
findshortwaybtn->setEnabled(false);
tips=new QLabel(this);
tips->setText(" 地图边长范围:15~50");
tips->setGeometry((N+2)*20,200,120,30);
tips->setStyleSheet("QLabel{background-color:rgb(122,154,255)};font-weight:bold;");
recounts=new QLabel(this);
QPixmap pixmap;
pixmap.load(":maze/image/counttime.jpg");
recounts->setPixmap(pixmap);
recounts->setScaledContents(true);
recounts->setGeometry((N+2)*20,70,120,50);
time=new QLabel(this);
time->setGeometry((N+2)*20,100,120,20);
toScore=new QLabel(this);
toScore->setGeometry((N+2)*20,130,120,20);
toScore->setStyleSheet("QLabel{background-color:rgb(250,128,114);font-size:22px;color:white;border-radius:5px;}");
toScore->setText(QString("得分:%1").arg(score));
map=new Maze*[M]; //初始化迷宫,节点全部设为墙壁
for(int i=0;i<M;i++)
{
map[i]=new Maze[N];
}
for(int i=0;i<M;i++)
{
for(int j=0;j<N;j++)
{
map[i][j].state=0;
map[i][j].i=i;
map[i][j].j=j;
}
}
connect(creatmazebtn,&QPushButton::clicked,this,&MazeWidget::creatmazebtnSlot);
connect(findshortwaybtn,&QPushButton::clicked,this,&MazeWidget::findshortwaybtnSlot);
}
void MazeWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QPen pen;
pen.setColor(QColor(Qt::yellow));
pen.setStyle(Qt::CustomDashLine);
painter.setPen(pen);
for(int i=FinalPath.size()-1;i>=0;i--)
{
map[FinalPath.at(i).i][FinalPath.at(i).j].state=2;
if(FinalPath.at(i).i==X&&FinalPath.at(i).j==Y) //清除走过的路的寻路痕迹
{
map[FinalPath.at(i).i][FinalPath.at(i).j].state=1;
FinalPath.pop_back();
}
}
if(paint_flag)
{
for(int i=0;i<M;i++)
{
for(int j=0;j<N;j++)
{
if(i==X&&j==Y) //画角色
{
painter.drawPixmap(j*20,i*20,20,20,QPixmap(":maze/image/character.png"));
}
else if(i==M-2&&j==N-2) //画金币
{
painter.drawPixmap(j*20,i*20,20,20,QPixmap(":maze/image/gold.png"));
}
else
{
switch(map[i][j].state)
{
case 0: //画墙壁
painter.drawPixmap(j*20,i*20,20,20,QPixmap(":maze/image/wall.jpg"));
break;
case 1: //画道路
painter.drawPixmap(j*20,i*20,20,20,QPixmap(":maze/image/road.png"));
break;
case 2: //画自动寻路路径
painter.setBrush(QBrush(QColor(250,128,114),Qt::SolidPattern));
painter.drawRect(QRect(j*20,i*20,20,20));
break;
}
}
}
}
}
}
MazeWidget::~MazeWidget()
{
delete ui;
}
void MazeWidget::CreatMaze() //创建迷宫节点矩阵
{
int i=3,j=3;
map[i][j].state=1;
int randDir=0;
Maze temp;
temp.i=i;
temp.j=j;
temp.state=1;
bool Up=true; //判断各个方向能否到达
bool Down=true;
bool Right=true;
bool Left=true;
while(1) //不断生成迷宫节点,直至栈为空
{
temp.i=i;
temp.j=j;
randDir=qrand()%4; //获取随机方向:0:上;1:右;2:下;3:左
switch(randDir)
{
case 0:
if(Up&&i>2&&map[i-2][j].state==0)
{
MazeStack.push(temp);
map[i-2][j].state=1;
map[i-1][j].state=1;
i=i-2;
int rand;
rand=qrand()%10;
if(rand>3)
{
Up=true;
Right=true;
Down=true;
Left=true;
}
else
{
Up=false;
Right=false;
Down=false;
Left=false;
}
}
else
{
Up=false;
}
break;
case 1:
if(Right&&j<N-3&&map[i][j+2].state==0)
{
MazeStack.push(temp);
map[i][j+2].state=1;
map[i][j+1].state=1;
j=j+2;
int rand;
rand=qrand()%10;
if(rand>3)
{
Up=true;
Right=true;
Down=true;
Left=true;
}
else
{
Up=false;
Right=true;
Down=false;
Left=true;
}
}
else
{
Right=false;
}
break;
case 2:
if(Down&&i<M-3&&map[i+2][j].state==0)
{
MazeStack.push(temp);
map[i+2][j].state=1;
map[i+1][j].state=1;
i=i+2;
int rand;
rand=qrand()%10;
if(rand>3)
{
Up=true;
Right=true;
Down=true;
Left=true;
}
else
{
Up=false;
Right=false;
Down=false;
Left=false;
}
}
else
{
Down=false;
}
break;
case 3:
if(Left&&j>2&&map[i][j-2].state==0)
{
MazeStack.push(temp);
map[i][j-2].state=1;
map[i][j-1].state=1;
j=j-2;
Up=true;
Right=true;
Down=true;
Left=true;
}
else
{
Left=false;
}
break;
}
if(!Up&&!Down&&!Right&&!Left) //四个方向都不能创建新节点
{
if(!MazeStack.empty()) //回溯
{
i=MazeStack.top().i;
j=MazeStack.top().j;
MazeStack.pop();
Up=true;
Down=true;
Right=true;
Left=true;
}
else return;
}
}
}
void MazeWidget::creatmazebtnSlot() //创建迷宫的槽函数
{
if(Xline->text().toInt()>=15&&Yline->text().toInt()>=15&&Xline->text().toInt()<=50&&Yline->text().toInt()<=50)
{
M=Xline->text().toInt(); //重新配置画面元素
N=Yline->text().toInt();
if(M%2==0) M--;
if(N%2==0) N--;
this->setFixedSize((N+10)*20,(M+1)*20);
Xline->setGeometry((N+2)*20+10,245,40,20);
Yline->setGeometry((N+2)*20+70,245,40,20);
creatmazebtn->setGeometry((N+2)*20,280,120,30);
findshortwaybtn->setGeometry((N+2)*20,20,120,30);
findshortwaybtn->setEnabled(true);
tips->setGeometry((N+2)*20,200,120,30);
recounts->setGeometry((N+2)*20,70,120,50);
time->setGeometry((N+2)*20,130,120,20);
time->setStyleSheet("QLabel{background-color:rgb(200,101,202);font-size:25px;color:white;}");
toScore->setGeometry((N+2)*20,160,120,20);
toScore->setText(QString("得分:%1").arg(score));
FinalPath.clear();
this->setFocus(Qt::MouseFocusReason);
X=1; //初始化
Y=1;
map=new Maze*[M];
for(int i=0;i<M;i++)
{
map[i]=new Maze[N];
}
for(int i=0;i<M;i++)
{
for(int j=0;j<N;j++)
{
map[i][j].state=0;
map[i][j].i=i;
map[i][j].j=j;
}
}
this->CreatMaze();
paint_flag=true;
update();
}
else
{
QMessageBox::information(this,"错误","输入的边长不在限制范围内!",QMessageBox::Yes);
Xline->clear();
Yline->clear();
}
this->killTimer(timerId);
timerId=this->startTimer(1000);
this->findshortwaybtnSlot(); //保证通路
useFindRoad=false;
FinalPath.clear();
while(!Box1Queue.empty())
{
Box1Queue.pop();
}
if(flag==false) creatmazebtnSlot();
disconnect(creatmazebtn,&QPushButton::clicked,this,&MazeWidget::creatmazebtnSlot);
}
void MazeWidget::keyPressEvent(QKeyEvent *e)
{
int temp;
if(e->key()==Qt::Key_W)
{
temp=X-1;
if(temp && map[temp][Y].state) X=temp;
}
else if(e->key()==Qt::Key_S)
{
temp=X+1;
if(temp<M-1 && map[temp][Y].state) X=temp;
}
else if(e->key()==Qt::Key_A)
{
temp=Y-1;
if(temp && map[X][temp].state) Y=temp;
}
else if(e->key()==Qt::Key_D)
{
temp=Y+1;
if(temp<N-1 && map[X][temp].state) Y=temp;
}
if(X==M-2 && Y==N-2) //到达终点
{
QSound *sound=new QSound(":/maze/image/getgold.wav",this);
sound->setLoops(1);
sound->play();
if(!useFindRoad)
{
QMessageBox::information(this,"恭喜","您获得了一枚金币!",QMessageBox::Yes);
toScore->setText(QString("得分:%1").arg(++score));
}
else
{
QMessageBox::information(this,"提示","您使用了自动寻路功能\n因此分数不增加!",QMessageBox::Yes);
useFindRoad=false;
}
for(int i=0;i<M;i++)
{
for(int j=0;j<N;j++)
{
map[i][j].state=0;
}
}
FinalPath.clear();
this->creatmazebtnSlot();
this->counttimeSlot();
}
update();
}
void MazeWidget::FindShortWay() //自动寻路
{
FinalPath.clear(); //删除已有自动寻路结果
while(!Box1Queue.empty())
{
Box1Queue.pop();
}
Maze maze[M][N];
int i,j;
for(i=0;i<M;i++)
{
for(j=0;j<N;j++)
{
maze[i][j].i=i;
maze[i][j].j=j;
maze[i][j].state=map[i][j].state;
}
}
int t=0,pos=0;
Box1 box;
box.i=X;
box.j=Y;
box.pre=-1;
box.num=t;
Box1Queue.push(box);
maze[X][Y].state=-1; //-1:已走过该节点;1:未走过该节点
Maze temp;
find=false;
flag=false;
while(!Box1Queue.empty()&&!find)
{
i=Box1Queue.front().i; //把队首的节点入栈
j=Box1Queue.front().j;
box.i=i;
box.j=j;
box.num=Box1Queue.front().num;
box.pre=Box1Queue.front().pre;
Box1Stack.push(box);
if(i==M-2&&j==N-2) //到达终点
{
find=true;
flag=true;
while(!Box1Stack.empty()) //按栈原路返回
{
temp.i=Box1Stack.top().i;
temp.j=Box1Stack.top().j;
temp.state=1;
FinalPath.push_back(temp);
pos=Box1Stack.top().pre;
while(!Box1Stack.empty()&&pos!=Box1Stack.top().num)
{
Box1Stack.pop();
}
}
}
int dire=0;
for(dire=0;dire<4;dire++) //0:上;1:右;2:下;3:左
{
switch(dire)
{
case 0:
i=Box1Queue.front().i-1;
j=Box1Queue.front().j;
break;
case 1:
i=Box1Queue.front().i;
j=Box1Queue.front().j+1;
break;
case 2:
i=Box1Queue.front().i+1;
j=Box1Queue.front().j;
break;
case 3:
i=Box1Queue.front().i;
j=Box1Queue.front().j-1;
break;
}
if(maze[i][j].state==1) //还未走过
{
t++;
box.i=i;
box.j=j;
box.num=t;
box.pre=Box1Queue.front().num;
Box1Queue.push(box);
maze[i][j].state=-1;
}
}
Box1Queue.pop();
}
}
void MazeWidget::findshortwaybtnSlot() //自动寻路的槽函数
{
useFindRoad=true;
for(int i=0;i<M;i++)
{
for(int j=0;j<N;j++)
{
if(map[i][j].state==2)
{
map[i][j].state=1;
}
}
}
FindShortWay();
update();
}
void MazeWidget::timerEvent(QTimerEvent *)
{
counttimeSlot();
}
void MazeWidget::counttimeSlot()
{
static int sec=180;
time->setText(QString("%1").arg(sec--));
if(time->text().toInt()==0)
{
this->killTimer(timerId);
int ret=QMessageBox::information(this,"游戏结束!","您本轮游戏获得的金币数为:"+QString::number(score)+"。\n点击确认键开始新一轮的游戏!",QMessageBox::Yes);
if(ret==QMessageBox::Yes)
{
this->creatmazebtnSlot();
connect(creatmazebtn,&QPushButton::clicked,this,&MazeWidget::creatmazebtnSlot);
}
sec=180;
score=0;
toScore->setText(QString("得分:%1").arg(score));
}
}