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

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值