一. 实现效果图:
初始:
箱子放到正确的位置:
游戏失败:
游戏成功:
二. 工程目录
三. 代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "map.h"
#include "person.h"
#include "postion.h"
#include <QMainWindow>
#include <QPaintEvent>
#include <QPainter>
#include <QKeyEvent>
#include <QDebug>
#include <QFont>
#include <QPen>
#define SCREEN_WIDTH 960 // 屏幕宽度
#define SCREEN_HEIGHT 768 // 屏幕高度
#define LINE 9 // 地图行数
#define COLUMN 12 // 地图列数
#define LEVEL 1 // 关卡
#define SIZE 61 // 格子(地图上墙,箱子...)尺寸
#define X_SHIFT 110 // x偏移量
#define Y_SHIFT 130 // y偏移量
#define BLACKGROUND_PATH ":/images/blackground" // 背景图片
#define WALL_PATH ":/images/wall" // 墙图片
#define FLOOR_PATH ":/images/floor" // 空地图片
#define DES_PATH ":/images/des" // 目的图片
#define MAN_PATH ":/images/man" // 人图片
#define BOX_PATH ":/images/box" // 箱子图片
#define BOX_1_PATH ":/images/box_1" // 箱子推到指定位置图片
#define MAX_STEP 65 // 最大步数限制
extern int map[LINE][COLUMN];
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
struct Person man; // 人的位置
struct Postion pre_pos; // 之前的位置
int step;
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void initmap();
void gameControl(enum Direction);
void changeMap(int line, int column, enum Map);
bool isOver();
protected:
void paintEvent(QPaintEvent *);
void keyPressEvent(QKeyEvent *);
public slots:
void gameOverControl();
void gameSuccessControl();
signals:
void change();
void gameover();
void gamesuccess();
};
#endif // MAINWINDOW_H
map.h
#ifndef MAP_H
#define MAP_H
#define LINE 9 // 地图行数
#define COLUMN 12 // 地图列数
enum Map { // 地图属性
WALL, // 墙
FLOOR, // 空地
DES, // 目的地
MAN, // 人
BOX, // 箱子
HIT, // 箱子到达目的地
NUL = -1 // 记录上一个位置
};
#endif // MAP_H
person.h
#ifndef PERSON_H
#define PERSON_H
struct Person {
int x; // 人所在行
int y; // 人所在列
};
enum Direction { //人的方向
UP,
DOWN,
LEFT,
RIGHT
};
#endif // PERSON_H
postion.h
#ifndef POSTION_H
#define POSTION_H
#include "map.h"
struct Postion {
Map p;
};
#endif // POSTION_H
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
initmap();
connect(this, SIGNAL(change()), this, SLOT(update()));
connect(this, SIGNAL(gameover()), this, SLOT(gameOverControl()));
connect(this, SIGNAL(gamesuccess()), this, SLOT(gameSuccessControl()));
}
MainWindow::~MainWindow()
{
}
/*
* 地图初始化函数
* 设置地图大小和标题
*/
void MainWindow::initmap() {
resize(SCREEN_WIDTH, SCREEN_HEIGHT); // 初始化屏幕高度宽度
setWindowIconText(QString("推箱子"));
step = 0;
pre_pos.p = NUL;
}
/*
* 游戏控制函数
* 输入参数:要前进的方向(UP, DOWN, LEFT, RIGHT)
*/
void MainWindow::gameControl(enum Direction direction) {
if (direction == UP) { // 上方向
if (map[man.x - 1][man.y] == FLOOR && pre_pos.p == NUL) { // 上方向为地板且脚下不是目的地
changeMap(man.x, man.y, FLOOR); // 原位置换为地板
changeMap(man.x - 1, man.y, MAN); // 上方向位置换为人
step++; // 步数++
} else if (map[man.x - 1][man.y] == BOX && map[man.x - 2][man.y] == FLOOR && pre_pos.p == NUL) { // 上方向为箱子,箱子上方向为地板, 且脚下不为目的地
changeMap(man.x, man.y, FLOOR);
changeMap(man.x - 1, man.y, MAN);
changeMap(man.x - 2, man.y, BOX);
step++;
} else if (map[man.x - 1][man.y] == BOX && map[man.x - 2][man.y] == DES) { // 上方向为箱子,箱子上方向为目的地
changeMap(man.x, man.y, FLOOR);
changeMap(man.x - 1, man.y, MAN);
changeMap(man.x - 2, man.y, HIT);
step++;
} else if (map[man.x - 1][man.y] == DES) { // 上方向为目的地
changeMap(man.x - 1, man.y, MAN);
changeMap(man.x, man.y, FLOOR);
pre_pos.p = DES;
step++;
} else if (map[man.x - 1][man.y] == FLOOR && pre_pos.p == DES) { // 上方向为地板且脚下为目的地
pre_pos.p = NUL;
changeMap(man.x, man.y, DES);
changeMap(man.x - 1, man.y, MAN);
step++;
} else if (map[man.x - 1][man.y] == HIT && map[man.x - 2][man.y] == FLOOR) { // 上方向为目的地且目的地上方为地板
changeMap(man.x, man.y, FLOOR);
changeMap(man.x - 1, man.y, MAN);
changeMap(man.x - 2, man.y, BOX);
pre_pos.p = DES;
step++;
} else if (map[man.x - 1][man.y] == BOX && map[man.x - 2][man.y] == FLOOR && pre_pos.p == DES) { // 上方向为箱子,且箱子上方为地板且脚下为目的地
changeMap(man.x, man.y, DES);
changeMap(man.x - 1, man.y, MAN);
changeMap(man.x - 2, man.y, BOX);
pre_pos.p = NUL;
step++;
}
} else if (direction == DOWN) {
if (map[man.x + 1][man.y] == FLOOR && pre_pos.p == NUL) {
changeMap(man.x, man.y, FLOOR);
changeMap(man.x + 1, man.y, MAN);
step++;
} else if (map[man.x + 1][man.y] == BOX && map[man.x + 2][man.y] == FLOOR && pre_pos.p == NUL) {
changeMap(man.x, man.y, FLOOR);
changeMap(man.x + 1, man.y, MAN);
changeMap(man.x + 2, man.y, BOX);
step++;
} else if (map[man.x + 1][man.y] == BOX && map[man.x + 2][man.y] == DES) {
changeMap(man.x, man.y, FLOOR);
changeMap(man.x + 1, man.y, MAN);
changeMap(man.x + 2, man.y, HIT);
step++;
} else if (map[man.x + 1][man.y] == DES) {
changeMap(man.x + 1, man.y, MAN);
changeMap(man.x, man.y, FLOOR);
pre_pos.p = DES;
step++;
} else if (map[man.x + 1][man.y] == FLOOR && pre_pos.p == DES) {
pre_pos.p = NUL;
changeMap(man.x, man.y, DES);
changeMap(man.x + 1, man.y, MAN);
step++;
} else if (map[man.x + 1][man.y] == HIT && map[man.x + 2][man.y] == FLOOR) {
changeMap(man.x, man.y, FLOOR);
changeMap(man.x + 1, man.y, MAN);
changeMap(man.x + 2, man.y, BOX);
pre_pos.p = DES;
step++;
} else if (map[man.x + 1][man.y] == BOX && map[man.x + 2][man.y] == FLOOR && pre_pos.p == DES) {
changeMap(man.x, man.y, DES);
changeMap(man.x + 1, man.y, MAN);
changeMap(man.x + 2, man.y, BOX);
pre_pos.p = NUL;
step++;
}
} else if (direction == LEFT) {
if (map[man.x][man.y - 1] == FLOOR && pre_pos.p == NUL) {
changeMap(man.x, man.y, FLOOR);
changeMap(man.x, man.y - 1, MAN);
step++;
} else if (map[man.x][man.y - 1] == BOX && map[man.x][man.y - 2] == FLOOR && pre_pos.p == NUL) {
changeMap(man.x, man.y, FLOOR);
changeMap(man.x, man.y - 1, MAN);
changeMap(man.x, man.y - 2, BOX);
step++;
} else if (map[man.x][man.y - 1] == BOX && map[man.x][man.y - 2] == DES) {
changeMap(man.x, man.y, FLOOR);
changeMap(man.x, man.y - 1, MAN);
changeMap(man.x, man.y - 2, HIT);
step++;
} else if (map[man.x][man.y - 1] == DES) {
changeMap(man.x, man.y - 1, MAN);
changeMap(man.x, man.y, FLOOR);
pre_pos.p = DES;
step++;
} else if (map[man.x][man.y - 1] == FLOOR && pre_pos.p == DES) {
pre_pos.p = NUL;
changeMap(man.x, man.y, DES);
changeMap(man.x, man.y - 1, MAN);
step++;
} else if (map[man.x][man.y - 1] == HIT && map[man.x][man.y - 2] == FLOOR) {
changeMap(man.x, man.y, FLOOR);
changeMap(man.x, man.y - 1, MAN);
changeMap(man.x, man.y - 2, BOX);
pre_pos.p = DES;
step++;
} else if (map[man.x][man.y - 1] == BOX && map[man.x][man.y - 2] == FLOOR && pre_pos.p == DES) {
changeMap(man.x, man.y, DES);
changeMap(man.x, man.y - 1, MAN);
changeMap(man.x, man.y - 2, BOX);
pre_pos.p = NUL;
step++;
}
} else if (direction == RIGHT) {
if (map[man.x][man.y + 1] == FLOOR && pre_pos.p == NUL) {
changeMap(man.x, man.y, FLOOR);
changeMap(man.x, man.y + 1, MAN);
step++;
} else if (map[man.x][man.y + 1] == BOX && map[man.x][man.y + 2] == FLOOR && pre_pos.p == NUL){
changeMap(man.x, man.y, FLOOR);
changeMap(man.x, man.y + 1, MAN);
changeMap(man.x, man.y + 2, BOX);
step++;
} else if (map[man.x][man.y + 1] == BOX && map[man.x][man.y + 2] == DES) {
changeMap(man.x, man.y, FLOOR);
changeMap(man.x, man.y + 1, MAN);
changeMap(man.x, man.y + 2, HIT);
step++;
} else if (map[man.x][man.y + 1] == DES) {
changeMap(man.x, man.y + 1, MAN);
changeMap(man.x, man.y, FLOOR);
pre_pos.p = DES;
step++;
} else if (map[man.x][man.y + 1] == FLOOR && pre_pos.p == DES) {
pre_pos.p = NUL;
changeMap(man.x, man.y, DES);
changeMap(man.x, man.y + 1, MAN);
step++;
} else if (map[man.x][man.y + 1] == HIT && map[man.x][man.y + 2] == FLOOR) {
changeMap(man.x, man.y, FLOOR);
changeMap(man.x, man.y + 1, MAN);
changeMap(man.x, man.y + 2, BOX);
pre_pos.p = DES;
step++;
} else if (map[man.x][man.y + 1] == BOX && map[man.x][man.y + 2] == FLOOR && pre_pos.p == DES) {
changeMap(man.x, man.y, DES);
changeMap(man.x, man.y + 1, MAN);
changeMap(man.x, man.y + 2, BOX);
pre_pos.p = NUL;
step++;
}
}
}
/*
* 判断游戏是否结束函数
* 当地图中所有DES被替换为HIT代表游戏结束
* 返回值:true为结束, false反之
*/
bool MainWindow::isOver() {
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < COLUMN; j++) {
if (map[i][j] == DES) return false;
}
}
return true;
}
/*
* 改变地图参数函数
* 改变参数同时发出change()信号, 关联update()函数对图进行渲染
* 输入:改变的行,列,变成的属性(墙,箱子,人等)
*/
void MainWindow::changeMap(int line, int column, enum Map m) {
map[line][column] = m;
emit change();
}
// 重写绘图事件
void MainWindow::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.drawPixmap(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, QPixmap(BLACKGROUND_PATH)); // 绘制背景
QFont font("方正舒体", 30, QFont::ExtraLight, false);
QPen pen;
pen.setColor(Qt::white);
painter.setPen(pen);
painter.setFont(font);
painter.drawText(40, 40, QString("剩余步数:%1").arg(MAX_STEP - step));
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < COLUMN; j++) {
switch (map[i][j]) {
case WALL: {
painter.drawPixmap(X_SHIFT + SIZE * j, Y_SHIFT + SIZE * i, SIZE, SIZE, QPixmap(WALL_PATH)); // 绘制墙
break;
}
case FLOOR: {
painter.drawPixmap(X_SHIFT + SIZE * j, Y_SHIFT + SIZE * i, SIZE, SIZE, QPixmap(FLOOR_PATH)); // 绘制空地
break;
}
case DES: {
painter.drawPixmap(X_SHIFT + SIZE * j, Y_SHIFT + SIZE * i, SIZE, SIZE, QPixmap(DES_PATH)); // 绘制目的地
break;
}
case MAN: {
painter.drawPixmap(X_SHIFT + SIZE * j, Y_SHIFT + SIZE * i, SIZE, SIZE, QPixmap(MAN_PATH)); // 绘制人
man.x = i; // 记录小人位置
man.y = j;
break;
}
case BOX: {
painter.drawPixmap(X_SHIFT + SIZE * j, Y_SHIFT + SIZE * i, SIZE, SIZE, QPixmap(BOX_PATH)); // 绘制箱子
break;
}
case HIT: {
painter.drawPixmap(X_SHIFT + SIZE * j, Y_SHIFT + SIZE * i, SIZE, SIZE, QPixmap(BOX_1_PATH));
break;
}
default:
break;
}
}
}
if (isOver()) {
painter.drawText((this->width()/2) - 40, this->height()/2, QString("任务成功!"));
emit gamesuccess();
}
if (step > MAX_STEP) {
painter.drawText((this->width()/2) - 40, this->height()/2, QString("任务失败!"));
emit gameover();
}
}
// 重写键盘事件
void MainWindow::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::Key_W) {
gameControl(UP);
} else if (event->key() == Qt::Key_A) {
gameControl(LEFT);
} else if (event->key() == Qt::Key_D) {
gameControl(RIGHT);
} else if (event->key() == Qt::Key_S) {
gameControl(DOWN);
} else if (event->key() == Qt::Key_Enter) {
} else {
}
}
void MainWindow::gameOverControl() {
disconnect(this, SIGNAL(change()), this, SLOT(update()));
}
void MainWindow::gameSuccessControl() {
disconnect(this, SIGNAL(change()), this, SLOT(update()));
}
map.cpp
#include "map.h"
int map[LINE][COLUMN] = { // 地图
{WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL},
{WALL, FLOOR, WALL, FLOOR, FLOOR, FLOOR, FLOOR, FLOOR, FLOOR, FLOOR, WALL, WALL},
{WALL, FLOOR, BOX, FLOOR, WALL, DES, FLOOR, WALL, DES, FLOOR, WALL, WALL},
{WALL, FLOOR, WALL, FLOOR, WALL, FLOOR, WALL, WALL, FLOOR, FLOOR, FLOOR, WALL},
{WALL, FLOOR, WALL, DES, WALL, FLOOR, FLOOR, BOX, FLOOR, FLOOR, FLOOR, WALL},
{WALL, FLOOR, FLOOR, FLOOR, WALL, MAN, FLOOR, FLOOR, FLOOR, BOX, FLOOR, WALL},
{WALL, FLOOR, DES, FLOOR, FLOOR, BOX, FLOOR, FLOOR, FLOOR, FLOOR, FLOOR, WALL},
{WALL, FLOOR, WALL, WALL, FLOOR, WALL, FLOOR, FLOOR, WALL, WALL, FLOOR, WALL},
{WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL}
};
四. GitHub链接