QT实现简单的2d游戏地图编辑器

QT实现简单的2d游戏地图编辑器

我写的这个地图编辑器主要实现了用键盘配合鼠标点击屏幕,间接生成一个二维数组,再将这个二维数组写入到文件中的操作,以直观、方便地对二维数组进行更改,以用作2d游戏的地图数组。

该程序最多向数组中添加19种(0-18)不同的数据。

运行效果:
创建初始地图界面:
在这里插入图片描述

地图编辑界面:
在这里插入图片描述

将地图数据写入到文件后地图信息界面:
在这里插入图片描述
除基本功能外,在程序中还实现了在按下移动鼠标左键时添加数据、按下移动鼠标右键时删除数据、自定义地图大小、使用文件对话框选择要保存的文件路径、将地图文件另存为、查看当前地图信息的功能。

虽然这些功能看似很多,且拥有这些功能的编辑器已经可以将地图数据用在2d小游戏的地图上,但我知道,这些距离一个专业、商业的2d编辑器还有着很远的差距。即使将比较对象换做“成熟好用功能齐全的2d编辑器”,该程序依然差了很多。

比如可以缩放编辑界面大小功能、自定义数值对应自定义颜色功能、添加数值功能、添加图片代表数值功能、添加背景图功能、选区设置数值功能等,这些功能的实现都是很复杂的,也是现在的我没有办法做到的。

编译环境:
Windows Qt 5.9.0 Qt Creator 4.3.0

思路:
将鼠标坐标分为地图宽高相乘个格子的区域,结构数组存储所有格子的格子坐标和对应的数值的信息,鼠标在点击时,将该区域格子在结构数组中的信息根据当前所选键值改变,并将数组中的信息按照颜色对应关系绘制矩形和数字到界面上。
使用键盘的0-9键代表0-9的地图数组中的数值,a-i代表10到18的地图数组中的数值,鼠标右键代表预设的地图默认数值。

下面展示程序的主要代码,如果你想查看项目的所有代码,可以私信博主发给你。


代码:

MainWindow.h 创建初始地图界面类头文件:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

MainWindow.cpp 创建初始地图界面类函数实现:

#include "MainWindow.h"
#include "ui_widget.h"
#include <QPushButton>
#include "mainfrom.h"
#include <QMouseEvent>  //鼠标事件

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //设置固定窗口大小
    setFixedSize(900,600);

    //设置标题
    setWindowTitle("2d地图编辑器");

    //监听确定按钮点击
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        this->close();          //当前窗口关闭
        //将文本框中的内容转换为数字传入新窗口对象构造函数中
        MainFrom *from = new MainFrom(ui->lineEdit->text().toInt(), ui->lineEdit_2->text().toInt(), ui->lineEdit_3->text().toInt());
        from->show();           //打开新窗口界面
    });
}

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

mainfrom.h 地图编辑界面类头文件:

#ifndef MAINFROM_H
#define MAINFROM_H

#include <QMainWindow>
#include <QPainter>     //画家类
#include <QLabel>       //标签
#include <QMouseEvent>  //鼠标事件
#include <Qvector>      //动态数组

class MainFrom : public QMainWindow
{
    Q_OBJECT
private:
    //绘图事件
    void paintEvent(QPaintEvent *);
    //鼠标按下事件
    void mousePressEvent(QMouseEvent *event);
    //鼠标移动事件
    void mouseMoveEvent(QMouseEvent *event);
    //键盘事件
    void keyPressEvent(QKeyEvent *ev);

    int MX = 0, MY = 0;         //最大宽高

    //创建标签控件
    QLabel *lab = new QLabel(this);

    int mi = 0, mj = 0;         //用于循环和确定地图坐标

    int key = 0;                //用于控制绘制的物体的属性的键值

    struct DataAttr             //数据值和颜色结构
#ifndef MAINFROM_H
#define MAINFROM_H

#include <QMainWindow>
#include <QPainter>     //画家类
#include <QLabel>       //标签
#include <QMouseEvent>  //鼠标事件
#include <Qvector>      //动态数组

class MainFrom : public QMainWindow
{
    Q_OBJECT
private:
    //绘图事件
    void paintEvent(QPaintEvent *);
    //鼠标按下事件
    void mousePressEvent(QMouseEvent *event);
    //鼠标移动事件
    void mouseMoveEvent(QMouseEvent *event);
    //键盘事件
    void keyPressEvent(QKeyEvent *ev);

    int MX = 0, MY = 0;         //最大宽高

    //创建标签控件
    QLabel *lab = new QLabel(this);

    int mi = 0, mj = 0;         //用于循环和确定地图坐标

    int key = 0;                //用于控制绘制的物体的属性的键值

    struct DataAttr             //数据值和颜色结构
    {
        int DKey;               //键值
        Qt::GlobalColor colorenum;          //颜色枚举值
    };

    //记录所有数据的对象的初始临时数组
    //(键值对应数字对应颜色表)
    const DataAttr TempDataArr[19] =
    {
        {0,Qt::darkCyan},{1,Qt::darkMagenta},{2,Qt::black},{3,Qt::darkGray},{4,Qt::gray},
        {5,Qt::lightGray},{6,Qt::red},{7,Qt::green},{8,Qt::blue},{9,Qt::cyan},
        {10,Qt::magenta},{11,Qt::yellow},{12,Qt::darkRed},{13,Qt::darkGreen},{14,Qt::darkBlue},
        {15,Qt::darkCyan},{16,Qt::darkMagenta},{17,Qt::darkYellow},{18,Qt::darkYellow}
    };

//    QVector<DataAttr> datacolorvec; //颜色对照数据动态数组

    DataAttr CurrSeleData = TempDataArr[0];      //记录当前选中的颜色对照结构

    struct KeyData                  //qtkey字符对应结构
    {
        Qt::Key qtkey;
        char ckey;
    };

    //Qt::key对应字符 数组
    const KeyData keyarr[19] =
    {
      {Qt::Key_0,'0'},{Qt::Key_1,'1'},{Qt::Key_2,'2'},{Qt::Key_3,'3'},{Qt::Key_4,'4'},
      {Qt::Key_5,'5'},{Qt::Key_6,'6'},{Qt::Key_7,'7'},{Qt::Key_8,'8'},{Qt::Key_9,'9'},
      {Qt::Key_A,'a'},{Qt::Key_B,'b'},{Qt::Key_C,'c'},{Qt::Key_D,'d'},{Qt::Key_E,'e'},
      {Qt::Key_F,'f'},{Qt::Key_G,'g'},{Qt::Key_H,'h'},{Qt::Key_I,'i'}
    };

    int **filemapdataarr = NULL;       //存储地图数组数据主要数组

    bool filesave = false;      //判断文件是否是第一次执行保存操作 false代表还未保存过

    QString path = "C:/Users/ASUS/Desktop";               //记录默认保存的文件路径

    const char DiaOpenDefa[30] = "./";      //文件对话框默认打开路径

    //保存文件函数
    void CSaveFileF();

    int MapDefault = -1;        //记录地图默认值

public:
//    explicit MainFrom(QWidget *parent = nullptr);
    //构造参数:地图宽高、地图默认值
    MainFrom(int MaxWidth, int MaxHeight, int MapDefault);

signals:

public slots:
};

#endif // MAINFROM_H


mainfrom.cpp 地图编辑界面类函数实现:

#include "mainfrom.h"
#include <QMessageBox>      //弹出对话框
#include <QCoreApplication> //退出应用程序
#include <QMenuBar>         //菜单栏
#include <QFile>            //文件读写
#include <QFileDialog>      //文件对话框
#include "instructionsuse.h"//使用说明窗口类
#include "keydescription.h" //键位说明窗口类
#include <QMessageBox>      //消息对话框
#include <QDebug>

MainFrom::MainFrom(int MaxWidth, int MaxHeight, int MapDefault)
{
    this->MapDefault = MapDefault;  //将传进来的地图默认值赋给类中的变量,以便于在其他函数使用

    if(!MaxWidth || !MaxHeight)     //如果两个值都是0则return
    {
        QMessageBox::critical(this, "错误", "输入错误");  //弹出错误对话框
        QCoreApplication::exit(0);   //退出应用程序
    }

    //记录参数
    MX = MaxWidth, MY = MaxHeight;

    filemapdataarr = new int* [MY];     //数组开辟第二维空间

    for(int i = 0; i < MY; i++)                     //数组开辟第二维空间
        filemapdataarr[i] = new int[MX];

    //为地图数组赋初值
    for(int j = 0 ; j < MY ; j++)
        for(int i = 0; i < MX; i++)
            filemapdataarr[j][i] = MapDefault;

    //根据参数固定窗口大小
    setFixedSize(MaxWidth << 5, (MaxHeight << 5) + 32 + 60);    //地图高 +菜单栏范围 +提示信息范围
    //设置标题
    setWindowTitle("编辑器操作界面");
    //创建菜单栏
    QMenuBar *bar = menuBar();
    //将菜单放入到窗口中
    setMenuBar(bar);
    //设置菜单栏字体属性
    bar->setFont(QFont("微软雅黑", 10));

    //创建菜单
    QMenu* saveMenu = bar->addMenu("文件");
    //创建菜单项
    saveMenu->addAction("保存");

    //监听保存菜单项按钮,执行保存操作
    connect(saveMenu,&QMenu::triggered,[=]()
    {
        //弹出文件对话框(只在第一次保存文件时执行)
        if(!filesave)
        {
            path = QFileDialog::getOpenFileName(this,"打开文件",DiaOpenDefa,"(*.txt)");
            CSaveFileF();   //保存文件函数
            filesave = true;
        }
        else
            CSaveFileF();   //保存文件函数
    });

    //创建菜单
    QMenu* SaveAsMenu = bar->addMenu("另存为");
    //创建菜单项
    SaveAsMenu->addAction("另存为");
    //监听另存为菜单项
    connect(SaveAsMenu,&QMenu::triggered,[=]()
    {
        path = QFileDialog::getOpenFileName(this,"打开文件",DiaOpenDefa,"(*.txt)"); //弹出对话框选择保存路径
        CSaveFileF();   //保存文件函数
    });


    QMenu* UseMenu = bar->addMenu("使用说明");
    UseMenu->addAction("使用说明");
    //监听使用说明菜单项
    connect(UseMenu,&QMenu::triggered,[=]()
    {
        InstructionsUse *use = new InstructionsUse();
        use->show();    //弹出使用说明窗口
    });

    QMenu* KeyUseMenu = bar->addMenu("键位说明");
    KeyUseMenu->addAction("说明");

    //监听键位说明菜单项
    connect(KeyUseMenu,&QMenu::triggered,[=]()
    {
        KeyDescription *kuse = new KeyDescription();
        kuse->show();    //弹出使用说明窗口
    });

    QMenu* MapInformation = bar->addMenu("地图信息");
    MapInformation->addAction("地图信息");

    //监听地图信息菜单项
    connect(MapInformation,&QMenu::triggered,[=]()
    {//用消息对话框显示当前地图信息
        QMessageBox::information(this, "地图信息",
        QString("当前地图宽高:%1  %2\n地图默认值:%3\n当前选中值:%4")
        .arg(MX).arg(MY).arg(this->MapDefault).arg(CurrSeleData.DKey));
    });

    //设置标签控件属性
    lab->move(14, 46);                      //移动控件
    lab->setFont(QFont("微软雅黑", 16));     //设置属性
    lab->setText("地图坐标:0  0");         //设置文本
    lab->resize(MX << 5, 28);               //设置大小

    //设置鼠标追踪
    setMouseTracking(true);
}

//保存文件函数
void MainFrom::CSaveFileF()
{

    qDebug() << "3333333333333333333333333333";
    QFile file(path);   //创建文件对象

    qDebug() << "44444444444444444444444444444444";

    //设置打开方式
    file.open(QIODevice::WriteOnly);    //写入方式打开

    qDebug() << "5555555555555555555555555";

    //将filemapdataarr中的信息写入到文件中
    for(int j = 0; j < MY; j++)
    {
        for(int i = 0; i < MX; i++)
            //参数转换为const char*
            file.write(QString("%1, ").arg(filemapdataarr[j][i]).toStdString().data());

        file.write("\n");
    }

qDebug() << "6666666666666666666666666";

    //关闭文件
    file.close();

qDebug() << "777777777777777777777777777";



    qDebug() << "9999999999999999999999999999";
}

//绘图事件
void MainFrom::paintEvent(QPaintEvent *)
{
    //创建画家对象,指定绘图设备为this窗口
    QPainter painter(this);

    //画出格子
    for(int i = 0; i < MX; i++)
        for(int j = 0; j < MY; j++)
            painter.drawRect(QRect(i * 32, j * 32 + 32 + 60, 32, 32));

    for(int j = 0; j < MY; j++)
        for(int i = 0; i < MX; i++)
        {   //画出数组中所有内容
            for(auto ti : TempDataArr)  //通过判断值,确定要使用显示的颜色
                if(ti.DKey == filemapdataarr[j][i])
                {
                    painter.setBrush(QBrush(ti.colorenum));  //使用画刷
                    break;
                }

            //如果是默认值且默认值不属于预设值,则使用特定的背景颜色画刷,
            if(filemapdataarr[j][i] == MapDefault && (MapDefault < 0 || MapDefault > 18))
                painter.setBrush(QBrush(QColor(240,240,240)));

            painter.drawRect(QRect(i * 32, j * 32 + 32 + 60, 32, 32));    //画出矩形

            //默认值不会显示数字
            if(filemapdataarr[j][i] == MapDefault)
                continue;

            //画出数字
            painter.setFont(QFont("黑体", 12, QFont::Bold));
            painter.drawText(QRect(i * 32 + 10, j * 32 + 32 + 60 + 8, 30, 20),
                             QString("%1").arg(filemapdataarr[j][i]));
        }
}

//鼠标按下事件
void MainFrom::mousePressEvent(QMouseEvent *event)
{
    //左键按下
    if (event->button() == Qt::LeftButton)
    {
        //将当前鼠标点击的数据插入到主要数据数组中
        if(CurrSeleData.DKey >= 0 && CurrSeleData.DKey <= 18 && mj >= 0 && mj < MY && mi >= 0 && mi < MX)   //加限制条件
            filemapdataarr[mj][mi] = CurrSeleData.DKey; //修改当前鼠标坐标的的对应值
        update();        //调用绘图函数
    }
    //右键按下, 删除按下位置的元素
    else if (event->button() == Qt::RightButton)
    {
        filemapdataarr[mj][mi] = this->MapDefault;     //修改为默认值
        update();       //调用绘图函数
    }
}

//鼠标移动事件
void MainFrom::mouseMoveEvent(QMouseEvent *event)
{
    //鼠标越界直接返回
    if(event->x() < 0 || event->x() > (MX << 5) || event->y() < 0 || event->y() > (MY << 5) + 32 + 60)
        return;

    for(mi = 0; mi < MX; mi++)      //确定鼠标坐标对应地图坐标
        for(mj = 0; mj < MY; mj++)
            if(event->x() >= (mi << 5) && event->x() < (mi << 5) + 32 &&
               event->y() >= (mj << 5) + 32 + 60 && event->y() < (mj << 5) + (32 << 1) + 60 )
            {
                lab->setText(QString("鼠标坐标:%1  %2").arg(mi + 1).arg(mj + 1)); //更新标签内容
                goto L1;    //跳出循环
            }
    L1:

    //鼠标左键按下且移动时,也执行插入数据操作
    if(event->buttons() & Qt::LeftButton)
    {
        if(CurrSeleData.DKey >= 0 && CurrSeleData.DKey <= 18 && mj >= 0 && mj < MY && mi >= 0 && mi < MX)
            filemapdataarr[mj][mi] = CurrSeleData.DKey; //修改当前鼠标坐标的的对应值
        update();
    }
    //右键同样删除
    else if(event->buttons() & Qt::RightButton)
    {
        filemapdataarr[mj][mi] = this->MapDefault;     //修改为默认值

        update();       //调用绘图函数
    }
}

//键盘事件
void MainFrom::keyPressEvent(QKeyEvent *ev)
{
    //组合键CTRL + S 用于保存地图数据快捷键
    if ((ev->modifiers() == Qt::ControlModifier) && (ev->key() == Qt::Key_S))
    {
        //弹出文件对话框(只在第一次保存文件时执行)
        if(!filesave)
        {
            path = QFileDialog::getOpenFileName(this,"打开文件",DiaOpenDefa,"(*.txt)");
            CSaveFileF();   //保存文件函数
            filesave = true;
            return;
        }
        CSaveFileF();       //保存文件
        return;
    }

    //程序默认对应键值共19个键,0 - 1  a - i
    //17种颜色,0和15、1和16、18和17共用一种颜色

    int ni;                 //将键值和表中值对应
    for(ni = 0; ni < 19; ni++)
        if(ev->key() == keyarr[ni].qtkey)
            break;

    if(ni >= 19)    //没找到键值时,返回
        return;

    CurrSeleData = TempDataArr[ni];    //将找到的结构赋给记录当前结构的变量
}




欢迎大家提出批评和建议,感谢支持。

原创文章 20 获赞 24 访问量 8344

猜你喜欢

转载自blog.csdn.net/qq_46239972/article/details/105882827
今日推荐