QT小游戏开发(马走日)示例

本文介绍了一个使用QT开发的棋盘寻路程序,实现了输入行数和列数自动生成网格棋盘,通过交互设置起点和终点,利用广度优先搜索算法动态显示最短路径。代码基于dialog框架,涉及信号槽、绘制更新等QT特性。

一、概述

        本次博客是为了记录大三时期做的一个实训,用QT开发的,感觉这个小软件用到了不少QT里面的东西,现在记录一下,以后需要用的时候看一下就很快能上手了。这里尤其是对信号槽,绘制更新等用得比较多。


二、功能和算法分析

本次小程序实现的功能有:

1. 输入行数和列数,自动生成网格棋盘;

2. 通过交互来设置起点和终点;

3. 寻找到最短的路径并一步一步动态的显示路径;

4. 可以读取棋盘文件来自动生成棋盘。

算法:

要找最短路径,很简单的就是使用广度优先搜索算法,利用队列来寻找最短路径,使用数组来存储棋盘,同时标记是否已经遍历过。

三、工程结构和目录

       使用的基本框架为dialog,基本所有的代码都是在dialog.cpp文件里编写。dialog.h里要声明很多函数和变量,还有很重要的槽函数,这些函数都要在dialog.cpp文件里实现出来。dialog.ui就是通过QT的界面绘制方式自动生成的文件,下面的Resources文件里存储的都是在界面中用到的图片文件。

四、代码

这里就直接上代码吧,最主要的目的还是为了找个地方存一下这些代码,为了以后用到相似的功能时可以更加快速的上手。

1.  .pro文件(QT)

#-------------------------------------------------
#
# Project created by QtCreator 2018-01-08T09:39:37
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = AlgorithmAnalisys
TEMPLATE = app


SOURCES += main.cpp\
        dialog.cpp

HEADERS  += dialog.h

FORMS    += dialog.ui

RESOURCES += \
    icon_1.qrc \
    start.qrc \
    final.qrc \
    jump.qrc \
    file.qrc \
    finish.qrc

这里注意到,要在.pro文件中添加RESOURCES的路径。

2. dialog.h文件

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QQueue>
#include <QStack>
#include <QTime>
#include <QVector>

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
    int rows=0;
    int cols=0;
    int N;
    int flag=-1;
    int rect_num1=-1;
    int rect_num2=-1;
    QQueue<int> queue;
    QStack<int> stack;
    int rect_jumpNo=-1;
    int l=0;
    QTimer *timer;
    int flag1=0;
private:
    Ui::Dialog *ui;
    QRect rect[1000];
    int a[1000];
    int b[500];
    void mousePressEvent(QMouseEvent *);
    void paintEvent(QPaintEvent *);
private slots:
    void finish();
    void final();
    void start();
    void jump();
    void update_jumpNo();
    void selectFile();

};

#endif // DIALOG_H

3. dialog.cpp文件

#include "dialog.h"
#include "ui_dialog.h"
#include <QRect>
#include <QPainter>
#include <iostream>
#include <QMouseEvent>
#include <QTimer>
#include <QString>
#include <QFileDialog>
#include <QMessageBox>
#include <QFile>
#include <QTextStream>
#include <QChar>
#include <QDebug>
using namespace std;

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(finish()));
    connect(ui->start,SIGNAL(clicked()),this,SLOT(start()));
    connect(ui->final_2,SIGNAL(clicked()),this,SLOT(final()));
    connect(ui->btn_jump,SIGNAL(clicked()),this,SLOT(jump()));
    connect(ui->btn_inputfile,SIGNAL(clicked()),this,SLOT(selectFile()));
}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::mousePressEvent(QMouseEvent *e)
{
    if(e->button()==Qt::LeftButton)
    {
        for(int i=0;i<N;i++)
        {
            if(rect[i].contains(e->pos()))
            {

                if(flag==0)
                {

                    rect_num1=i;
                    a[(rect_num1/cols+2)*(cols+4)+rect_num1%cols+2]=-2;
                }

                if(flag==1)
                {
                    rect_num2=i;
                    a[(rect_num2/cols+2)*(cols+4)+rect_num2%cols+2]=-3;
                }

                break;
            }
        }
    }
    update();

}

void Dialog::paintEvent(QPaintEvent *)
{
    QPainter paint(this);
    if(flag==-1)
    {
        paint.setBrush(Qt::white);
        paint.drawRects(rect,N);
    }
    if(flag==0)
    {
        paint.setBrush(Qt::white);
        paint.drawRects(rect,N);
        paint.setBrush(Qt::blue);
        paint.drawRect(rect[rect_num1]);
    }
    if(flag==1)
    {
        paint.setBrush(Qt::white);
        paint.drawRects(rect,N);
        paint.setBrush(Qt::blue);
        paint.drawRect(rect[rect_num1]);
        paint.setBrush(Qt::white);

        paint.setBrush(Qt::red);
        paint.drawRect(rect[rect_num2]);
    }

    if(flag==4)
    {
        paint.setBrush(Qt::black);
        paint.drawRect(rect[rect_jumpNo]);
    }
    //cout<<"Hello"<<endl;
}

void Dialog::finish()
{
    stack.clear();
    disconnect(timer,SIGNAL(timeout()),this,SLOT(update_jumpNo()));

    if(flag1==0)
    {
        rows=ui->lineEdit->text().toInt();
        cols=ui->lineEdit_2->text().toInt();
    }
    else
        flag1=0;
    N=rows*cols;
    int width=ui->widget->width()/cols;
    int height=ui->widget->height()/rows;
    int x=ui->widget->x();
    int y=ui->widget->y();

    for(int i=0;i<2;i++)
    {
        for(int j=0;j<cols+4;j++)
            a[i*(cols+4)+j]=-1;
    }
    for(int i=rows+2;i<rows+4;i++)
    {
        for(int j=0;j<cols+4;j++)
            a[i*(cols+4)+j]=-1;
    }
    for(int i=2;i<rows+2;i++)
    {
        for(int j=0;j<2;j++)
            a[i*(cols+4)+j]=-1;
        for(int j=cols+2;j<cols+4;j++)
            a[i*(cols+4)+j]=-1;
    }

    for(int i=0;i<rows;i++)
    {
        for(int j=0;j<cols;j++)
        {
            rect[i*cols+j]=QRect(x,y,width,height);
            a[(i+2)*(cols+4)+j+2]=0;
            x+=width;
        }
        x=ui->widget->x();
        y+=height;
    }

    flag=-1;
    update();

}

void Dialog::start()
{
    flag=0;
}

void Dialog::final()
{
    flag=1;
}

void Dialog::jump()
{
    queue.clear();
    stack.clear();
    disconnect(timer,SIGNAL(timeout()),this,SLOT(update_jumpNo()));
    bool finish=false;
    int start=-2;
    int final=-3;
    int current_pos;
    for(int i=0;i<(rows+4)*(cols+4);i++)
    {
        if(a[i]==-2)
        {
            start=i;
            queue.push_back(i);
            break;
        }
    }
    for(int i=0;i<(rows+4)*(cols+4);i++)
    {
        if(a[i]==-3)
        {
            final=i;
            break;
        }
    }
     ui->label_3->setText("正在搜寻路径...");

    while(!queue.isEmpty())
    {
        int pos=queue.dequeue();
        // queue.pop_front();
        current_pos=pos;
        cout<<pos<<" ";
        if(pos==final)
        {
            stack.push(final);
            int lastStep=final;
            while(true)
            {
                lastStep=a[lastStep];
                if(lastStep==start)
                {
                    finish=true;
                    break;
                }
                else
                {
                    stack.push(lastStep);
                }
            }
            break;
        }
        int next_pos1=(current_pos/(cols+4)-2)*(cols+4)+(current_pos%(cols+4)+1);
        if(a[next_pos1]==0||a[next_pos1]==-3)
        {
            queue.enqueue(next_pos1);
            a[next_pos1]=current_pos;
        }

        int next_pos2=(current_pos/(cols+4)-1)*(cols+4)+(current_pos%(cols+4)+2);
        if(a[next_pos2]==0||a[next_pos2]==-3)
        {
            queue.enqueue(next_pos2);
            // queue.push_back(next_pos2);
            a[next_pos2]=current_pos;
        }

        int next_pos3=(current_pos/(cols+4)+1)*(cols+4)+(current_pos%(cols+4)+2);
        if(a[next_pos3]==0||a[next_pos3]==-3)
        {
            queue.enqueue(next_pos3);
            a[next_pos3]=current_pos;
        }

        int next_pos4=(current_pos/(cols+4)+2)*(cols+4)+(current_pos%(cols+4)+1);
        if(a[next_pos4]==0||a[next_pos4]==-3)
        {
            queue.enqueue(next_pos4);
            a[next_pos4]=current_pos;
        }

        int next_pos5=(current_pos/(cols+4)+2)*(cols+4)+(current_pos%(cols+4)-1);
        if(a[next_pos5]==0||a[next_pos5]==-3)
        {
            queue.enqueue(next_pos5);
            a[next_pos5]=current_pos;
        }

        int next_pos6=(current_pos/(cols+4)+1)*(cols+4)+(current_pos%(cols+4)-2);
        if(a[next_pos6]==0||a[next_pos6]==-3)
        {
            queue.enqueue(next_pos6);
            a[next_pos6]=current_pos;
        }

        int next_pos7=(current_pos/(cols+4)-1)*(cols+4)+(current_pos%(cols+4)-2);
        if(a[next_pos7]==0||a[next_pos7]==-3)
        {
            queue.enqueue(next_pos7);
            a[next_pos7]=current_pos;
        }

        int next_pos8=(current_pos/(cols+4)-2)*(cols+4)+(current_pos%(cols+4)-1);
        if(a[next_pos8]==0||a[next_pos8]==-3)
        {
            queue.enqueue(next_pos8);
            a[next_pos8]=current_pos;
        }
    }

    if(finish)
    {
        timer=new QTimer(this);
        connect(timer,SIGNAL(timeout()),this,SLOT(update_jumpNo()));
        timer->start(1000);
        flag=4;
        //        int i=0;
        //        flag==4;
        //        while(!stack.isEmpty())
        //        {
        //            b[i]=stack.top();
        //            stack.pop();

        //           // rect_jumpNo=(b[i]/(cols+4)-2)*cols+b[i]%(cols+4)-2;
        //            cout<<b[i]<<" ";
        //        }
        //        cout<<endl;
    }
    else
        ui->label_3->setText("无法顺利到达终点");
}

void Dialog::update_jumpNo()
{
    if(!stack.isEmpty())
    {
        b[l]=stack.top();
        stack.pop();
        rect_jumpNo=(b[l]/(cols+4)-2)*cols+b[l]%(cols+4)-2;
        update(QRegion(rect[rect_jumpNo]));
        l++;
    }
    else
    {
        QString str=QString::number(l);
        ui->label_3->setText(("顺利到达终点,最短需要\n跳"+str+"步"));
        disconnect(timer,SIGNAL(timeout()),this,SLOT(update_jumpNo()));
        ui->lineEdit->setText("");
        ui->lineEdit_2->setText("");
        l=0;

    }

}

void Dialog::selectFile()
{
    flag1=1;
    QString fileName = QFileDialog :: getOpenFileName(this, NULL, NULL, "*.h *.cpp *.txt");
    //---打开文件并读取文件内容
    QFile file(fileName);

    //--打开文件成功
    if (file.open(QIODevice ::ReadOnly | QIODevice ::Text))
    {
        QTextStream textStream(&file);

        QString str;

        rows=0;
        cols=0;
        str=textStream.readLine();
        rows++;
        for( int i=0;i<str.length();i++)
        {
            if(str.at(i)==' ')
            {
                cols++;
            }
        }
        while(!textStream.atEnd())
        {
            str=textStream.readLine();
            rows++;
        }
        ui->label_3->setText("已读入文件");


    }
    else    //---打开文件失败
    {
        QMessageBox ::information(NULL, NULL, "open file error");
    }


}

4. main.cpp文件

#include "dialog.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog w;
    w.show();

    return a.exec();
}

5. UI界面

五、效果演示

1. 设置行数和列数,绘制棋盘;设置起点和终点,起点为蓝色,终点为红色。

先输入行数和列数,然后点击绘制棋盘按钮。然后点击设置起点按钮,并在右侧棋盘中选择一个方格作为起点,同样再选择一个终点。

2. 点击开始跳按钮

3. 路径寻找完毕

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值