目录
各位小伙伴们大家好,我是今天第一次发CSDN的mdr,我这几天用Qt做了个小型沙盒游戏,但是还没有做完,我把我的制作过程分享给大家,希望可以有所帮助;同时我也希望大佬们可以指出程序中的不足,我会努力完善
我电脑坏了,呜呜呜
这篇博客先断更一段时间,等电脑修好的吧
开发环境
1. Qt的安装
我用的是Qt 5.14.2版本,下载地址为 点击链接
如图所示,网站提供了三个版本:Windows对应.exe,Linux对应.dmg,MacOS对应.run
还可以使用qt在线安装工具下载最新版本 点击链接
2. Inno Setup
Inno Setup是一个免费的 Windows 安装程序制作软件,可进行构建-编译制作安装包。下载链接
如图所示,点击红框内链接进行下载
代码编写
1. 新建项目
演示版本:Qt 5.14.2 QtCreator 4.11.1
-
选择“Qt Widgets Application”
-
选择项目路径
注意不要选择带中文的路径,会报错 -
“build system” 就选“qmake”
-
把窗口的基类改成“QWidget”
-
“translation” 无需更改
-
Select all kits可以选中, qt会帮我们自动配置项目
-
一直点“下一步”,直到项目创建完成
2. 类的创建
- main.cpp (Qt已经帮我们创建好了)
- widget.h (Qt已经帮我们创建好了)
- widget.cpp (Qt已经帮我们创建好了)
- mblock.h
- mblock.cpp
- mworld.h
- mworld.cpp
- mplayer.h
- mplayer.cpp
3. UI设计
- 新建项目时,Qt为我们创建了一个空的名字叫widget.ui的UI文件,如图
- Qt 为我们提供了很多常用的控件,例如label(一个可以显示文字的标签)和button(按钮)
- 首先,把窗口的大小固定成800*800:
- 点击mininumSize左边的小三角,如图所示:
把“宽度”和“高度”都改成800,如图所示: - 同理,把maxinumSize也改成800*800
- 点击mininumSize左边的小三角,如图所示:
- 我们的页面总共有这样几个组件:
+ Label,显示文本;
+ PushButton,按钮;
+ Vertical Layout(纵向布局)和Horizontal Layout(横向布局) - 把页面分为两个部分:
- 上半部分宽800,高600,显示世界的方块;
- 下半部分宽800,高600,显示游戏的基本信息:
- 镐子和斧头的等级,还有增加等级的按钮;
- 当前所处的x y坐标;
- 系统信息(当某些操作错误的时候的提示信息)
- 快捷栏位置: 1-镐子,2-斧头,3-铲子,4-方块(方块后面备注当前的默认方块种类);
- 背包打开/关闭
(未完待续)
4. 代码填充
- 方块设定(详情见
mblock.h
的注释) - 世界生成(参见
MWorld::MWorld()
):- 世界由
100
*100
=10000
个方块构成,所以建立一个二维数组; - 最下层是基岩;
- 世界分为两侧“平原”和中央“高原”,高原的起止点由
mountainBegin
和mountainEnd
决定; - 生成每一位置上面的海拔,储存在
int height[100]
里面;- 在平原和高原中部,后一格的海拔随机执行以下三种操作:比前面高一格;和前面相同;比前面矮一格
- 在高原开始处,后一格的海拔随机执行以下三种操作:比前面高一格;和前面相同;比前面高两格
- 在高原结束处,后一格的海拔随机执行以下三种操作:比前面低一格;和前面相同;比前面低两格
- 在每一格的海拔高度填充一格草(
blocks[height[i]][i].init(52);
);在草的上面填满空气;在草的下面填充两格泥土(blocks[height[i]+2][i].init(51); blocks[height[i]+1][i].init(51);
);在泥土下面填满石头; - 生成树:隔4~11格,设置一个“树”的位置;随机生成小树和大树;
- 世界由
- 玩家设计
- 拥有的方块数量:
std::map<int, int> blocks
:因为方块编号不能重复,所以使用索引不重复的map; - 镐子等级(
int pickaxeLevel
)和斧头等级(int axeLevel
); - 背包的打开或关闭(
bool backpackOpen
):打开为true,关闭为false; - 快捷栏位置(
int hand
); - 默认方块的编号(
int defaultBlock
):游戏开始时,默认方块为none;玩家可以打开背包,切换默认方块;当快捷栏位于4(block
)且满足放置方块的要求时,点击右键会放置默认方块;
- 拥有的方块数量:
- 游戏行为:
- 升级镐子和斧头:
- 放置方块:
- 破坏方块:
(未完待续)
5. 代码
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QPaintEvent>
#include "mworld.h"
#include "mplayer.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
void keyPressEvent(QKeyEvent *event);
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
private slots:
void on_pushButtonPickaxe_clicked();
void on_pushButtonAxe_clicked();
private:
Ui::Widget *ui;
MWorld *world;
MPlayer *player;
QColor defaultBlockColor;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
ui->setupUi(this);
this->setWindowTitle("Mdr's sandbox game");
world = new MWorld();
player = new MPlayer();
defaultBlockColor = 0xdddddd;
}
Widget::~Widget() {
delete ui; }
void Widget::keyPressEvent(QKeyEvent *event) {
ui->labelSystem->setText("System message:");
if (this->player->backpackOpen) {
if (event->key() == Qt::Key_B) {
this->player->backpackOpen = !this->player->backpackOpen;
this->ui->labelBackpack->setText(
this->player->backpackOpen ? "backpack: open" : "backpack: closed");
}
} else {
auto key = event->key();
if (key == Qt::Key_W) {
// move up
if (this->player->hand == 4) {
if (this->world->blocks[this->world->x - 1][this->world->y].id == 1) {
bool ok = this->player->useBlock();
if (ok) {
this->world->move(1);
this->world->blocks[this->world->x + 1][this->world->y].init(
this->player->defaultBlock);
}
}
}
} else if (key == Qt::Key_S) {
// move down
} else if (key == Qt::Key_A) {
// move left
this->world->move(3);
} else if (key == Qt::Key_D) {
// move right
this->world->move(4);
} else if (key == Qt::Key_Q) {
// move right
this->world->move(5);
} else if (key == Qt::Key_E) {
// move right
this->world->move(6);
} else if (key == Qt::Key_B) {
this->player->backpackOpen = !this->player->backpackOpen;
this->ui->labelBackpack->setText(
this->player->backpackOpen ? "backpack: open" : "backpack: closed");
} else if (key == Qt::Key_1) {
this->player->hand = 1;
} else if (key == Qt::Key_2) {
this->player->hand = 2;
} else if (key == Qt::Key_3) {
this->player->hand = 3;
} else if (key == Qt::Key_4) {
this->player->hand = 4;
}
ui->labelHand->setText("hand: " + QString::number(this->player->hand));
this->world->fall();
}
update();
}
void Widget::mousePressEvent(QMouseEvent *event) {
ui->labelSystem->setText("System message:");
int x = event->x();
int y = event->y();
if (event