1.menu.h
#ifndef MENU_H
#define MENU_H
#include <QWidget>
#include <maze_widget.h>
#include <QPropertyAnimation>
#include <mylabel.h>
#include <QDebug>
namespace Ui {
class menu;
}
class menu : public QWidget
{
Q_OBJECT
public:
explicit menu(QWidget *parent = nullptr);
~menu();
Ui::menu *ui;
private slots:
void on_quit_button_clicked();
void on_ts_model_clicked();
private:
void mousePressEvent(QMouseEvent* event);
};
#endif // MENU_H
2.maze_widget.h
#ifndef MAZE_WIDGET_H
#define MAZE_WIDGET_H
#include <QWidget>
#include <QPainter>
#include <QPointF>
#include <QTimer>
#include <cstring>
#include <algorithm>
#include <QPixmap>
#include <QDebug>
#include <QKeyEvent>
#include <queue>
#include <QMessageBox>
#include <menu.h>
#include <QThread>
#define mapWidth 80
#define mapHeigh 80
struct squ
{
QRectF coo;
std::pair<int,int> rel_coo;
int if_wall; //0为路 1为墙 2为边界
int if_find_way; //是否为答案路径 1是抵达终点的路径 3是马里奥追到玩家的路径
};
QT_BEGIN_NAMESPACE
namespace Ui { class maze_Widget; }
QT_END_NAMESPACE
class maze_Widget : public QWidget
{
Q_OBJECT
public:
maze_Widget(QWidget *parent = nullptr);
~maze_Widget();
int RANK;
std::pair<int,int> player_coo;//玩家坐标
void map_generate(std::pair<int,int>,int);
protected:
void keyPressEvent(QKeyEvent *event);
void paintEvent(QPaintEvent *event);
void map_dfs(std::pair<int,int>,int);
bool find_bfs(std::pair<int,int>,std::pair<int,int>); //判断是否可以抵达终点
std::pair<int,int> find_way(std::pair<int,int>,std::pair<int,int>);
// std::pair<int,int> find(std::pair<int,int>); //寻找某点所在路径编号
private slots:
void player_move(); //玩家移动动画
void cop_catch();
void rule();
void g_time();
void map_dynamic();
private:
Ui::maze_Widget *ui;
QTimer * ai_move,* cop_move,*game_rule,*game_time,*map_d;
bool game_start;
int nodeWidth = 80; //单位尺寸
int nodeHeight = 80;
squ beg,fin; //起点与终点
squ **map = new squ *[mapWidth];
// std::pair<int,int> **p = new std::pair<int,int> *[mapWidth];
std::pair<int,int> cop_coo; //警察
std::pair<int,int> lj[mapWidth][mapHeigh]; //lj[i][j]表示抵达(i,j)的上一个点
int player_dir=0; //玩家朝向0为左 1为右
bool if_showay=false;
bool if_findway = false;
bool if_k = false,if_p = true,if_j = false,if_l = false;
int game_model;
int gametime;
bool if_cheat = false,if_dynamic = false; //判断作弊
};
#endif // MAZE_WIDGET_H
3.menu.cpp
#include "menu.h"
#include "ui_menu.h"
menu::menu(QWidget *parent) :
QWidget(parent),
ui(new Ui::menu)
{
ui->setupUi(this);
setFixedSize(800,800);
ui->menu_label->setPixmap(QPixmap(":/new/prefix1/picture/player_right_1.png"));
ui->menu_label->setScaledContents(true);
QWidget::setMouseTracking(true);
//生成背景图片
QImage background = QImage(":/new/prefix1/picture/bj2.jpg");
QBrush *brush = new QBrush(background.scaled(this->size()));
QPalette pa(this->palette());
pa.setBrush(QPalette::Window,*brush);
this->setPalette(pa);
}
menu::~menu()
{
delete ui;
}
void menu::on_quit_button_clicked()
{
this->close();
}
void menu::on_ts_model_clicked()
{
maze_Widget * game = new maze_Widget(0);
this->close();
game->show();
}
void menu::mousePressEvent(QMouseEvent *event)
{
if(ui->menu_frame->pos().x()==800)
{
QPropertyAnimation * ani = new QPropertyAnimation(ui->menu_frame,"pos");
ani->setDuration(200);
ani->setStartValue(QPoint(ui->menu_frame->pos().x(),390));
ani->setEndValue(QPoint(600,390));
ani->start();
}
else
{
QPropertyAnimation * ani = new QPropertyAnimation(ui->menu_frame,"pos");
ani->setDuration(200);
ani->setStartValue(QPoint(ui->menu_frame->pos().x(),390));
ani->setEndValue(QPoint(800,390));
ani->start();
}
}
4.maze_widget.cpp
#include "maze_widget.h"
#include "ui_maze_widget.h"
#include "md_thread.h"
maze_Widget::maze_Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::maze_Widget)
{
ui->setupUi(this);
setFixedSize(11*nodeWidth,11*nodeHeight);//固定尺寸
//生成背景图片
QImage background = QImage(":/new/prefix1/picture/bj4.jpg");
QBrush *brush = new QBrush(background.scaled(this->size()));
QPalette pa(this->palette());
pa.setBrush(QPalette::Window,*brush);
this->setPalette(pa);
//初始化地图和难度
for(int i=0;i<mapWidth;i++)
{
map[i] = new squ[mapHeigh];
// p[i] = new std::pair<int,int> [mapHeigh];
}
RANK = 4;
beg = {map[2][mapHeigh-1].coo,{2,mapHeigh-1},0,1}; //生成起点位置
map[beg.rel_coo.first][beg.rel_coo.second] = beg;
map_generate(beg.rel_coo,RANK);
//初始化难度
// game_model = model;
//初始化人物
player_coo = beg.rel_coo;
cop_coo = {-1,-1};
ai_move = new QTimer;
cop_move = new QTimer;
game_rule = new QTimer;
game_time = new QTimer;
map_d = new QTimer;
connect(ai_move,SIGNAL(timeout()),this,SLOT(player_move()));
connect(cop_move,SIGNAL(timeout()),this,SLOT(cop_catch()));
connect(game_rule,SIGNAL(timeout()),this,SLOT(rule()));
connect(game_time,SIGNAL(timeout()),this,SLOT(g_time()));
connect(map_d,SIGNAL(timeout()),this,SLOT(map_dynamic()));
//判断终点
if(find_bfs(fin.rel_coo,beg.rel_coo))if_findway = true,qDebug()<<if_findway;
else if_findway = false,qDebug()<<if_findway;
for(int i = 0;i<mapWidth;i++)
for(int j = 0;j<mapHeigh;j++)
map[i][j].if_find_way = 0;
//设置游戏开始
game_start = true;
game_rule->start(20);
game_time->start(1000);
//设置秒表
ui->time_num->setDigitCount(3);
ui->time_num->setDecMode();
ui->time_num->setStyleSheet("border: none");
ui->time_num->setSegmentStyle(QLCDNumber::Flat);
gametime = 0;
}
maze_Widget::~maze_Widget()
{
delete ui;
}
void maze_Widget::paintEvent(QPaintEvent *)
{
QPixmap pix_q_sm,pix_db_sm,pix_player_l,pix_player_r,pix_q_sl_1,pix_q_sl_2,pix_db_sl,pix_cop;
pix_q_sm.load(":/new/prefix1/picture/sm_q.jpg"); //沙漠墙
pix_q_sl_1.load(":/new/prefix1/picture/sl_q_1.jpg"); //森林墙1
pix_q_sl_2.load(":/new/prefix1/picture/sl_q_2.jpg"); //森林墙2
pix_db_sm.load(":/new/prefix1/picture/sm_d.jpg"); //沙漠地板
pix_db_sl.load(":/new/prefix1/picture/sl_d.jpg"); //森林地板
pix_player_l.load(":/new/prefix1/picture/player_left_1.png");
pix_player_r.load(":/new/prefix1/picture/player_right_1.png");
pix_cop.load(":/new/prefix1/picture/cop_1.png");
QPainter painter(this); //设置画笔
painter.setRenderHint(QPainter::Antialiasing,true); //抗锯齿
for(int i=0;i<11;i++)
{
for(int j=0;j<11;j++)
{
if(player_coo.first-5+i>=0&&player_coo.second-5+j>=0&&player_coo.first-5+i<=mapWidth-1&&player_coo.second-5+j<=mapHeigh-1)
{
switch(map[player_coo.first+i-5][player_coo.second+j-5].if_wall){
case 0:
painter.drawPixmap(i*nodeWidth,j*nodeHeight,nodeWidth,nodeHeight,pix_db_sl);
break;
case 1:
painter.drawPixmap(i*nodeWidth,j*nodeHeight,nodeWidth,nodeHeight,pix_q_sl_1);
break;
case 2:
painter.drawPixmap(i*nodeWidth,j*nodeHeight,nodeWidth,nodeHeight,pix_q_sl_2);
break;
}
if(if_showay&&map[player_coo.first+i-5][player_coo.second+j-5].if_find_way==1)
painter.drawPixmap(i*nodeWidth,j*nodeHeight,nodeWidth,nodeHeight,pix_db_sm);
if(map[player_coo.first+i-5][player_coo.second+j-5].if_find_way==3)
painter.drawPixmap(i*nodeWidth,j*nodeHeight,nodeWidth,nodeHeight,pix_db_sm);
}
}
}
switch (player_dir) {
case 0:
painter.drawPixmap(5*nodeWidth,5*nodeHeight,nodeWidth,nodeHeight,pix_player_l);//画人物
break;
case 1:
painter.drawPixmap(5*nodeWidth,5*nodeHeight,nodeWidth,nodeHeight,pix_player_r);//画人物
break;
}
if(cop_coo.first!=-1)
{
painter.drawPixmap((cop_coo.first-player_coo.first+5)*nodeWidth,(cop_coo.second-player_coo.second+5)*nodeHeight,nodeWidth,nodeHeight,pix_cop);//画警察
}
// qDebug()<<"左上角坐标"<<player_coo.first-5<<" "<<player_coo.second-5;
}
void maze_Widget::keyPressEvent(QKeyEvent *event)
{
switch(event->key())
{
case Qt::Key_W: //W键
if(player_coo.second>0&&!map[player_coo.first][player_coo.second-1].if_wall)
player_coo.second-=1;
break;
case Qt::Key_A: //A键
player_dir = 0;
if(player_coo.first>0&&!map[player_coo.first-1][player_coo.second].if_wall)
player_coo.first-=1;
break;
case Qt::Key_S: //S键
if(player_coo.second<mapHeigh-1&&!map[player_coo.first][player_coo.second+1].if_wall)
player_coo.second+=1;
break;
case Qt::Key_D: //D键
player_dir = 1;
if(player_coo.first<mapWidth-1&&!map[player_coo.first+1][player_coo.second].if_wall)
player_coo.first+=1;
break;
case Qt::Key_J: //动态地图
if_dynamic = true;
if(!if_j)
{
if_j = true;
// QEventLoop eventloop;
// QTimer::singleShot(2000, &eventloop, SLOT(quit())); //wait 2s
// eventloop.exec();
map_d->start(10000);
}
else map_d->stop(),if_j = false;
break;
case Qt::Key_P: //自动寻路或暂停
if_cheat = true;
if(!if_p)ai_move->stop(),if_p = true;
else if(if_findway)
{
for (int i=0;i<mapWidth;i++)
{
for (int j=0;j<mapHeigh;j++)
{
map[i][j].if_find_way = 0;
}
}
if_p = false,find_bfs(fin.rel_coo,player_coo),ai_move->start(100);
}
break;
case Qt::Key_K: //显示路径
if_cheat = true;
if(!if_k&&if_findway)
{
for (int i=0;i<mapWidth;i++)
{
for (int j=0;j<mapHeigh;j++)
{
map[i][j].if_find_way = 0;
}
}
find_bfs(fin.rel_coo,player_coo),if_k = true,if_showay = true;
}
else if_showay = false,if_k = false;
break;
case Qt::Key_L: //启动追逐
if(!if_l)
{
if_l = true;
QEventLoop eventloop;
QTimer::singleShot(2000, &eventloop, SLOT(quit())); //wait 2s
eventloop.exec();
cop_coo = beg.rel_coo;
cop_move->start(200);
}
break;
}
update();
}
void maze_Widget::map_dfs(std::pair<int, int> t,int RANK)
{
// map[t.first][t.second].if_wall = 0;
// if(t.first==mapWidth-1)return ;
int direction[4][2] = { { 1,0 },{ -1,0 },{ 0,1 },{ 0,-1 } };
for (int i = 0; i < 4; i++) {
int r = rand() % 4;
std::swap(direction[0][0],direction[r][0]);
std::swap(direction[0][1],direction[r][1]);
}
//向四个方向开挖
for (int i = 0; i < 4; i++) {
int dx = t.first;
int dy = t.second;
qDebug()<<"209"<<i<<t;
//控制挖的距离,由Rank来调整大小
int range = 1 + (RANK == 0 ? 0 : rand() % RANK);
qDebug()<<"212"<<range<<t;
while (range>0) {
dx += direction[i][0];
dy += direction[i][1];
qDebug()<<"216"<<dx<<dy<<t;
//排除掉回头路和围墙
if (map[dx][dy].if_wall!=1) {
break;
}
qDebug()<<"221"<<i<<range<<t;
//判断是否挖穿路径
int count = 0;
for (int j = dx - 1; j <= dx + 1; j++) {
for (int k = dy - 1; k <= dy + 1; k++) {
//abs(j - dx) + abs(k - dy) == 1 确保只判断九宫格的四个特定位置
if (std::abs(j - dx) + std::abs(k - dy) == 1 && !map[j][k].if_wall) {
count++;
}
}
}
if (count > 1) {
break;
}
//确保不会挖穿时,前进
range--;
map[dx][dy].if_wall=0;
// qDebug()<<" 挖到"<<map[dx][dy].rel_coo;
}
//没有挖穿危险,以此为节点递归
if (range <= 0) {
// srand(time(NULL));
map_dfs({dx,dy},RANK);
qDebug()<<"244"<<t;
}
}
}
void maze_Widget::map_generate(std::pair<int,int> b,int rank)
{
//初始化地图(边界内全为墙)
for(int i=0;i<mapWidth;i++)
{
for(int j=0;j<mapHeigh;j++)
{
map[i][j].rel_coo = {i,j};
QPointF lefttop = QPointF(i*nodeWidth,j*nodeHeight);
QPointF rightbotom = QPointF(i*nodeWidth+nodeWidth,j*nodeHeight+nodeHeight);
map[i][j].coo = QRectF(lefttop,rightbotom);
map[i][j].if_wall = 1;
map[i][j].if_find_way = 0;
}
}
for(int i=0;i<mapWidth;i++)
{
map[i][0].if_wall = 2;
map[i][mapHeigh-1].if_wall = 2;
}
for(int i=0;i<mapHeigh;i++)
{
map[0][i].if_wall = 2;
map[mapWidth-1][i].if_wall = 2;
}
map[b.first][b.second].if_wall = 0;
map[b.first][b.second].if_find_way = 1;
//dfs生成地图
map_dfs(b,rank);
//寻找终点位置
for (int i = 0; i <mapHeigh; i++) {
if (map[mapWidth-2][i].if_wall==0) {
map[mapWidth-1][i].if_wall=0;
fin = map[mapWidth-1][i];
break;
}
}
// map[beg.rel_coo.first][beg.rel_coo.second-1].if_wall = 0;
// map[fin.rel_coo.first-1][fin.rel_coo.second].if_wall = 0;
// for(int i=0;i<mapWidth;i++)
// for(int j=0;j<mapHeigh;j++)
// if(!map[i][j].if_wall)
// p[i][j] = {i,j};
// p[beg.rel_coo.first][beg.rel_coo.second] = {2,mapHeigh-2};
// p[fin.rel_coo.first][fin.rel_coo.second] = {mapWidth-2,2};
// srand(time(NULL));
// qDebug()<<"115";
// while (find({beg.rel_coo.first,beg.rel_coo.second})!=find({fin.rel_coo.first,fin.rel_coo.second}))
// {
// int x = rand()%mapWidth;
// int y = rand()%mapHeigh;
// int dx[4] = {-1,0,1,0};
// int dy[4] = {0,1,0,-1};
// //拆墙
// if(map[x][y].if_wall==1)
// {
// qDebug()<<"拆墙"<<x<<"^"<<y;
// bool if_comb = false;
// map[x][y].if_wall = 0;
// for(int i=0;i<4;i++)
// if(x+dx[i]>=0&&x+dx[i]<mapWidth&&y+dy[i]>=0&&y+dy[i]<mapHeigh&&map[x+dx[i]][y+dy[i]].if_wall==0)
// {
// p[find({x,y}).first][find({x,y}).second] = find({x+dx[i],y+dy[i]});
// if_comb = true;
// break;
// }
// if(!if_comb)p[x][y] = {x,y};
// }
// }
}
std::pair<int,int> maze_Widget::find_way(std::pair<int,int> t,std::pair<int,int> q)
{
if(q==player_coo)map[t.first][t.second].if_find_way = 1;
else map[t.first][t.second].if_find_way = 3;
if(t==q)return t;
if(t.first>=mapWidth||t.first<0||t.second>=mapHeigh||t.second<0||map[t.first][t.second].if_wall)return {-1,-1};
return find_way(lj[t.first][t.second],q);
}
bool maze_Widget::find_bfs(std::pair<int,int> sub_fin,std::pair<int,int> p)
{
int d[mapWidth][mapHeigh]; //定义某个点第几次被搜到(即到起点距离为几)
std::queue<std::pair<int,int>> qu;
qu.push(p); //队头从玩家位置开始
memset(d,-1,sizeof d); //初始化所有点,表示都没被搜索到
d[p.first][p.second]=0;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1}; //上下左右
while(!qu.empty()) //当队列不空
{
auto t=qu.front();
qu.pop();
for(int i=0;i<4;i++)
{
int x=t.first+dx[i],y=t.second+dy[i]; //遍历上下左右四个操作
if(x>=0&&x<mapWidth&&y>=0&&y<mapHeigh&&map[x][y].if_wall==0&&d[x][y]==-1) //如果不出界且可以走且没走到过
{
d[x][y]=d[t.first][t.second]+1; //就让这个点到起点的距离比队头到起点的距离多1
lj[x][y] = t;
qu.push({x,y}); //将这个点入队
}
}
}
if(find_way(sub_fin,p).first==-1)return false;
else return true;
}
void maze_Widget::player_move()
{
int dx[4] = {0,1,0,-1};
int dy[4] = {1,0,-1,0};
for(int i=0;i<4;i++)
{
if(player_coo.first+dx[i]>=0&&player_coo.first+dx[i]<=mapWidth-1&&player_coo.second+dy[i]>=0&&player_coo.second+dy[i]<=mapHeigh-1)
{
if(map[player_coo.first+dx[i]][player_coo.second+dy[i]].if_find_way==1)
{
map[player_coo.first][player_coo.second].if_find_way = 2;
player_coo = {player_coo.first+dx[i],player_coo.second+dy[i]};
}
}
}
update();
}
void maze_Widget::cop_catch()
{
map[cop_coo.first][cop_coo.second].if_find_way=3;
int dx[4] = {0,1,0,-1};
int dy[4] = {1,0,-1,0};
for(int i=0;i<4;i++)
{
if(cop_coo.first+dx[i]>=0&&cop_coo.first+dx[i]<=mapWidth-1&&cop_coo.second+dy[i]>=0&&cop_coo.second+dy[i]<=mapHeigh-1)
{
if(map[cop_coo.first+dx[i]][cop_coo.second+dy[i]].if_find_way==3)
{
map[cop_coo.first][cop_coo.second].if_find_way = 4;
cop_coo = {cop_coo.first+dx[i],cop_coo.second+dy[i]};
}
if(map[cop_coo.first+dx[i]][cop_coo.second+dy[i]].rel_coo==player_coo)
cop_coo = {cop_coo.first+dx[i],cop_coo.second+dy[i]};
}
}
update();
}
void maze_Widget::rule()
{
if(cop_coo.first!=-1)
{
game_time->stop();
gametime = 0;
ui->time_num->display(gametime);
find_bfs(player_coo,cop_coo);
}
if(cop_coo==player_coo)
{
game_rule->stop();
game_time->stop();
map_d->stop();
game_start = false,cop_move->stop(),qDebug()<<"game over";
QMessageBox::information(this,"游戏结束!","你被恶魔制服了!");
}
if(fin.rel_coo==player_coo)
{
game_start = false,cop_move->stop(),qDebug()<<"game win";
game_rule->stop();
game_time->stop();
map_d->stop();
if(cop_coo.first!=-1)
QMessageBox::information(this,"游戏结束!","冒险者,你成功逃脱了恶魔的追捕!");
else if(!if_cheat)
{
if(gametime<999)
{
QString m = "本次用时"+QString::number(gametime)+"秒";
QMessageBox::information(this,"游戏结束!",m);
}
else
QMessageBox::information(this,"游戏结束!","冒险者,你绕迷糊了!");
}
else
{
QMessageBox::information(this,"游戏结束!","冒险者,请动用自己的智慧完成迷宫!");
}
}
if(!game_start)
{
menu *m = new menu();
this->close();
m->show();
}
}
void maze_Widget::g_time()
{
ui->time_num->display(gametime++);
if(gametime==999)game_time->stop();
}
void maze_Widget::map_dynamic()
{
map_generate(player_coo,RANK);
update();
QEventLoop eventloop;
QTimer::singleShot(500, &eventloop, SLOT(quit())); //wait 0.5s
eventloop.exec();
if(!if_p)find_bfs(fin.rel_coo,player_coo);
}
main.cpp和.qrc和.ui文件略