Qt实现简单的推箱子游戏

2 篇文章 0 订阅

一. 实现效果图:

初始:

箱子放到正确的位置: 

游戏失败: 

游戏成功:

二. 工程目录

三.  代码

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链接

https://github.com/supermario19/QT-BOX_MAN-/tree/Version2.0

  • 20
    点赞
  • 138
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
以下是一个简单C++ 实现推箱子游戏的代码,其中用数字表示地图和物品: ``` #include <iostream> #include <vector> using namespace std; const int MAXN = 10; int n, m; int sx, sy; // 起点坐标 int ex, ey; // 终点坐标 int mp[MAXN][MAXN]; // 地图 int vis[MAXN][MAXN]; // 记录点是否访问过 vector<pair<int, int>> boxs; // 记录箱子位置 bool dfs(int x, int y) { if (x == ex && y == ey) return true; // 到达终点 if (mp[x][y] == 1 || vis[x][y]) return false; // 障碍或已访问过 vis[x][y] = 1; // 标记为已访问 for (int i = 0; i < boxs.size(); ++i) { int bx = boxs[i].first, by = boxs[i].second; if (bx == x && by == y) { // 当前位置有箱子 int nx = bx + (bx - x), ny = by + (by - y); if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue; // 超出边界 if (mp[nx][ny] == 1 || vis[nx][ny]) continue; // 障碍或已访问过 boxs[i].first = nx, boxs[i].second = ny; // 移动箱子 bool flag = dfs(x, y); // 从新位置开始搜索 boxs[i].first = bx, boxs[i].second = by; // 恢复箱子位置 if (flag) return true; // 可以到达终点 else continue; // 不可到达终点,继续搜索下一个箱子 } } if (x + 1 < n && !vis[x+1][y]) { // 向下搜索 if (dfs(x+1, y)) return true; } if (x - 1 >= 0 && !vis[x-1][y]) { // 向上搜索 if (dfs(x-1, y)) return true; } if (y + 1 < m && !vis[x][y+1]) { // 向右搜索 if (dfs(x, y+1)) return true; } if (y - 1 >= 0 && !vis[x][y-1]) { // 向左搜索 if (dfs(x, y-1)) return true; } return false; // 无法到达终点 } int main() { cin >> n >> m; for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { cin >> mp[i][j]; if (mp[i][j] == 2) boxs.push_back(make_pair(i, j)); // 记录箱子位置 else if (mp[i][j] == 3) sx = i, sy = j; // 记录起点坐标 else if (mp[i][j] == 4) ex = i, ey = j; // 记录终点坐标 } } if (dfs(sx, sy)) cout << "Yes" << endl; else cout << "No" << endl; return 0; } ``` 该算法使用 DFS(深度优先搜索)实现,对于每个箱子位置,向四个方向搜索箱子可移动的位置,然后以新位置为起点继续搜索,直到找到终点或无法继续搜索为止。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值