Qt实现一个连连看小游戏

为了实现连连看游戏,我们需要以下步骤:

  1. 绘制游戏界面:使用QT提供的QGraphicsView和QGraphicsScene绘制游戏界面,包括背景、方块等元素。
  2. 加载方块图片:通过QPixmap加载不同类型的方块图片,并在游戏场景中放置它们。
  3. 实现方块消除逻辑:当玩家点击两个相同类型的方块时,我们需要判断它们之间是否存在一条可连接路径。如果是,则可以将它们从场景中移除并增加分数;否则,提示无法消除。
  4. 实现难度级别设置:通过控制难度级别来改变游戏中出现的方块种类和数量,使得游戏更具挑战性。
  5. 添加音效和动画效果:为了增强用户体验,我们可以添加一些音效和动画效果,如点击声音、爆炸特效等。

下面是一个简单的QT实现连连看游戏的示例代码:

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

#include <QtWidgets>

class GameWidget : public QGraphicsView {
public:
    GameWidget(QWidget* parent = nullptr) : QGraphicsView(parent) {
        scene_ = new QGraphicsScene(this);
        setScene(scene_);
        setRenderHint(QPainter::Antialiasing);
        setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

        // 加载方块图片
        QPixmap pix(":/images/block.png");
        for (int i = 0; i < kNumBlockTypes; ++i) {
            block_pix_[i] = pix.copy(i * kBlockSize, 0, kBlockSize, kBlockSize);
        }

        // 初始化游戏场景
        InitGameScene();
    }

protected:
    void mousePressEvent(QMouseEvent* event) override {
        QGraphicsView::mousePressEvent(event);

        if (event->button() == Qt::LeftButton) {
            QPointF pos = mapToScene(event->pos());
            int row = static_cast<int>(pos.y() / kBlockSize);
            int col = static_cast<int>(pos.x() / kBlockSize);

            // 如果点击的是有效位置,则进行方块消除操作
            if (row >= 0 && row < kNumRows && col >= 0 && col < kNumCols &&
                !board_[row][col].isNull()) {
                if (selected_block_ == nullptr) {
                    selected_block_ = &board_[row][col];
                    selected_pos_ = QPoint(row, col);
                } else {
                    // 如果点击的是另一个相同类型的方块,则尝试进行连接操作
                    if (*selected_block_ == board_[row][col]) {
                        QPoint end_pos(row, col);
                        if (CanConnect(selected_pos_, end_pos)) {
                            RemoveBlocks(selected_pos_, end_pos);
                            UpdateScore(kRemoveScorePerPair);
                        }
                    }

                    selected_block_ = nullptr;
                }
            }
        }
    }

private:
    void InitGameScene() {
        QBrush bg_brush(QColor(240, 240, 240));
        scene_->setBackgroundBrush(bg_brush);

        // 在游戏场景中添加方块
        for (int r = 0; r < kNumRows; ++r) {
            for (int c = 0; c < kNumCols; ++c) {
                int block_type = qrand() % kNumBlockTypes;
                QPixmap pix = block_pix_[block_type];
                QGraphicsPixmapItem* item =
                    scene_->addPixmap(pix.scaled(kBlockSize, kBlockSize));
                item->setPos(c * kBlockSize, r * kBlockSize);
                board_[r][c] = Block(block_type, item);
            }
        }

        // 初始化得分和选中的方块
        score_ = 0;
        selected_block_ = nullptr;

        // 显示得分信息
        score_item_ = new QGraphicsTextItem(QString("Score: %1").arg(score_));
        QFont font("Arial", 16);
        score_item_->setFont(font);
        scene_->addItem(score_item_);
    }

    bool CanConnect(const QPoint& start_pos, const QPoint& end_pos) const {
        if (!IsPositionValid(start_pos) || !IsPositionValid(end_pos)) {
            return false;
        }

        // 如果两个方块类型不同,则不能连接
        if (board_[start_pos.x()][start_pos.y()].type !=
            board_[end_pos.x()][end_pos.y()].type) {
            return false;
        }

        // 如果两个位置相同,则不能连接
        if (start_pos == end_pos) {
            return false;
        }

        // 检查是否存在一条可连接路径
        QVector<QPoint> path;
        bool can_connect =
            FindPath(start_pos.x(), start_pos.y(), end_pos.x(), end_pos.y(), path);

#ifdef DEBUG_OUTPUT
    qDebug() << "CanConnect:" << start_pos << end_pos << can_connect;
#endif

    return can_connect;
}

bool FindPath(int start_row, int start_col, int end_row, int end_col,
              QVector<QPoint>& path) const {
    // 如果起点和终点相同,则已找到一条路径
    if (start_row == end_row && start_col == end_col) {
        return true;
    }

    // 如果起点或终点不合法,则无法连接
    if (!IsPositionValid(start_row, start_col) || !IsPositionValid(end_row, end_col)) {
        return false;
    }

    // 如果起点和终点类型不同,则无法连接
    if (board_[start_row][start_col].type != board_[end_row][end_col].type) {
        return false;
    }

    // 如果当前位置已经访问过,则无需再次访问
    if (visited_[start_row][start_col]) {
        return false;
    }

#ifdef DEBUG_OUTPUT
    qDebug() << "FindPath:" << QPoint(start_row, start_col)
             << QPoint(end_row, end_col);
#endif

    visited_[start_row][start_col] = true;

    // 检查四个方向是否存在可行的连接路径
    bool found_path = false;
    if (CanConnectTo(start_row - 1, start_col, end_row, end_col)) {  // 上方向
        found_path = FindPath(start_row - 1, start_col, end_row, end_col, path);
        if (found_path) {
            path.push_front(QPoint(start_row - 1, start_col));
            return true;
        }
    }
    
   ...

private:
// 游戏场景中的方块类型信息,包括方块类型和对应的QGraphicsPixmapItem
struct Block {
    int type;  // 方块类型,从0到kNumBlockTypes-1
    QGraphicsPixmapItem* item;  // 对应的QGraphicsPixmapItem

    Block(int t, QGraphicsPixmapItem* i) : type(t), item(i) {}

    bool operator==(const Block& other) const { return type == other.type; }

    bool isNull() const { return item == nullptr; }
};

static const int kBlockSize = 50;
static const int kNumRows = 8;
static const int kNumCols = 12;
static const int kNumBlockTypes = 6;
static const int kRemoveScorePerPair = 10;

QGraphicsScene* scene_;
QGraphicsTextItem* score_item_;            // 显示得分信息的文本项
int score_;                                // 当前得分
Block board_[kNumRows][kNumCols];          // 游戏场景中的方块信息
QPixmap block_pix_[kNumBlockTypes];        // 不同类型方块的图片
Block* selected_block_ = nullptr;          // 当前选中的方块
QPoint selected_pos_;                      // 当前选中的位置(在board_数组中的下标)
bool visited_[kNumRows][kNumCols]{};       // 记录当前访问状态,防止死循环

void UpdateScore(int delta_score) {
    score_ += delta_score;
    score_item_->setPlainText(QString("Score: %1").arg(score_));
}

bool CanConnectTo(int row, int col, int end_row, int end_col) const {
    return IsPositionValid(row, col) && !visited_[row][col] &&
           (row == end_row || col == end_col) &&
           board_[row][col].type == board_[end_row][end_col].type;
}

bool IsPositionValid(int row, int col) const {
    return row >= 0 && row < kNumRows && col >= 0 && col < kNumCols &&
           !board_[row][col].isNull();
}

bool IsPositionValid(const QPoint& pos) const {
    return IsPositionValid(pos.x(), pos.y());
}

void RemoveBlocks(const QPoint& start_pos, const QPoint& end_pos) {
    // 将连接路径上的方块从场景中移除
    QVector<QPoint> path;
    FindPath(start_pos.x(), start_pos.y(), end_pos.x(), end_pos.y(), path);
    for (const auto& p : path) {
        QGraphicsPixmapItem* item = board_[p.x()][p.y()].item;
        scene_->removeItem(item);
        delete item;
        board_[p.x()][p.y()] = Block(-1, nullptr);  // 空位置用-1表示
    }
}

};

int main(int argc, char** argv)
{
   QApplication app(argc, argv);

   GameWidget widget;
   widget.resize(600, 400);
   widget.show();

   return app.exec();
}

以上是一个简单的QT实现连连看游戏的示例代码,仅供参考。实际应用中还需要进一步优化和完善,如添加菜单、保存/加载游戏状态等功能。

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

猜你喜欢

转载自blog.csdn.net/m0_73443478/article/details/131111394