基于QT的推箱子小游戏

目录

前言

一、开发准备

二、实现过程

1.地图

2.读入数据

3.主控制对象

总结


前言

        这是基于QT开发一款推箱子小游戏,游戏规则大致是利用方向控制键(W:上、 S:下、 A :左、D:右)将箱子推进对应的洞坑中,将所有的箱子推进去了,游戏就结束了。在游戏整个过程中,人物不能穿过障碍物,不能拉箱子等操作。

一、开发准备

        对于这款游戏,大致需要有以下部分:地图,角色,主控制对象。其中地图元素包括路、障碍物等;角色元素包括了角色的位置,方向等;控制对象负责整个游戏控制工作,如控制角色移动、地图和角色元素绘制地点等。对于一款游戏而言,我们先需要了解我们对于整个项目组成的各个部分,先将对应对象或者元素做出,在结合整个调试。

二、实现过程

1.地图

        首先地图元素里面以下部分:路、障碍物、箱子、洞、进洞。这里可以用一个枚举变量表示这些元素。

    enum MapElement
    {
        Road,
        Wall,
        Box,
        Point,
        InPoint,
    };

        地图初始化时,我们需要读取每一个关的地图所包含的元素,这时候我就需要地图读取资源函数,将信息读出来,储存在一个二维数组当中(这里选取二维数组原因是:利用二维数组很好表示一个2D地图元素的横坐标和纵坐标),这时我们可以根据读取文件或者二维数组的内容(这里我们直接用定义全局变量的二维数组定义地图资源,也可以在项目下利用文件定义),显示不同关卡的地图样式,从而设定不同难度级别。

//读取地图资源
bool Map::ReadMap(void)
{
    for(int i = 0;i < map_Row;i++)
    {
        for(int j = 0;j < map_Col;j++)//遍历列
        {
            map_Map[i][j] = map_Grade1[i][j];//这里可以根据关卡不同,设定不同二维数组
        }
    }
    return true;
}

        将地图资源读取完后,我们就需要对所有的地图元素进行绘制,利用不同图片将路,路、障碍物等绘出,这里是利用QT图形绘制功能,将地图各种图片对象绘制出来,这里需要注意几点:1、如果你的地图中各元素对象图片不一样大小,这时就需要对坐标进行一些处理,下面代码就有体现了这一点;2 可以对绘制图片进行优化,我这里在地图开始绘制前就把路给铺好,在下面遍历循环时,就不需要绘制路的图片,还可以利用新旧是否变换,进行是否需要重绘。

void Map::DrawMap(QPainter* mPainter)
{  
    //全部铺路
    for(int i = 0;i < map_Row;i++)//行
    {
        for(int j = 0;j < map_Col;j++)//列
        {
            QString imgUrl = ":/new/prefix1/images/block.gif";
            mPainter->drawImage(35*j,35*i,QImage(imgUrl));
        }
    }

    for(int i = 0;i < map_Row;i++)//行
    {
        for(int j = 0;j < map_Col;j++)//列
        {
           // qDebug()<<mMap->map_Map[i][j];
            QString imgUrl;
            switch (map_Map[i][j])
            {
                case Map::Road:
                imgUrl = ":/new/prefix1/images/block.gif";
                break;
                case Map::Wall:
                imgUrl = ":/new/prefix1/images/wall.png";
                break;
                case Map::Box:
                imgUrl = ":/new/prefix1/images/box.png";
                break;
                case Map::Point:
                imgUrl = ":/new/prefix1/images/ball.png";
                break;
                case Map::InPoint:
                imgUrl = ":/new/prefix1/images/box.png";
                break;
            }
            int x = QImage(imgUrl).width() < 35 ? 35*j+2:35*j;
            int y = QImage(imgUrl).height()>35 ? 35*i-(QImage(imgUrl).height() - 35):35*i;

            if (imgUrl != ":/new/prefix1/images/block.gif")//如果不是路就绘画
            {
                mPainter->drawImage(x,y,QImage(imgUrl));
            }
        }
    }
}

2.读入数据

        角色包括了角色的移动和绘制,以及角色的绘制。我这里是将角色图片分为四张图片,上、下、左、右,这样就可以显示对应角色方向时,呈现给我们一种视觉上位置变换效果,这里代码比较简单,直接放出整段代码。

#include "role.h"

Role::Role(QObject *parent) : QObject(parent)
{
    R_Row = 8;
    R_Col = 8;
    R_Dir = Down;
}
void Role::DrawRole(QPainter* mPainter,int Dir) //绘制角色
{
    //确地角色的显示方位
    QString imgUrl;
    switch (Dir)
    {
    case Up:
        imgUrl = ":/new/prefix1/images/up.png";
        break;
    case Down:
        imgUrl = ":/new/prefix1/images/down.png";
        break;
    case Left:
        imgUrl = ":/new/prefix1/images/left.png";
        break;
    case Right:
        imgUrl = ":/new/prefix1/images/right.png";
        break;
    }
    int x = 35*R_Col - (QImage(imgUrl).width() - 35)/2;
    int y = 35*R_Row - (QImage(imgUrl).height() - 35);
    mPainter->drawImage(x,y,QImage(imgUrl));
}
//角色移动
void Role::MoveRole(int D_Row,int D_Col)
{
    R_Row += D_Row;//横坐标
    R_Col += D_Col;//纵坐标
}
#ifndef ROLE_H
#define ROLE_H

#include <QObject>
#include <QObject>
#include <QPoint>
#include <QPainter>

class Role : public QObject
{
    Q_OBJECT
public:
    explicit Role(QObject *parent = nullptr);

    enum
    {
        Up,
        Down,
        Left,
        Right,
    };
    int R_Row;
    int R_Col;

    int R_Dir;

    void DrawRole(QPainter* mPainter,int Dir); //绘制角色
    void MoveRole(int D_Row,int D_Col);//角色移动

signals:

};

#endif // ROLE_H

3.主控制对象

        主控制对象则是控制整个代码的运作,创建对象,控制规则等,这里采用了 Widget作为空窗口。首先初始化地图元素和人物元素。

   //初始化地图元素
    mMap = new Map(this);//创建一个游戏地图对象
    mMap->ReadMap();
    mMap->map_pos = QPoint(300,400);
    //初始化人物元素
    mRole = new Role();

      创建画家和定时器对象,画家负责整个资源的绘制过程,定时器则负责定时更新绘制间隔和判断胜利的时间间隔。

    mPainter = new QPainter(this);//创建画家
    mTimer = new QTimer(this);
    mTimer->start(10);
    connect(mTimer,&QTimer::timeout,[this](){this->update();});

    mTimer1 = new QTimer(this);
    mTimer1->start(1000);
    connect(mTimer1,&QTimer::timeout,[this](){this->IsWin();});

        推箱子逻辑是下面代码,就是判断人物前方是否有墙等情况,用层if else语句列举出来各种情况,从而改变对应地图元素。

//碰撞函数
void Widget::IsCollide(int _dRow,int _dCol)
{
    int newRow = mRole->R_Row + _dRow;
    int newCol = mRole->R_Col + _dCol;

    if (mMap->map_Map[newRow][newCol] == 1)//判断人物前方是否墙
    {
        mRole->MoveRole(0,0);
    }
    else if (mMap->map_Map[newRow][newCol] == 2)//判断前方是否箱子
    {
        if (mMap->map_Map[newRow+_dRow][newCol+_dCol] == 0)//判断箱子前方是否路
        {
            mMap->map_Map[newRow][newCol] = 0;//把箱子变成路元素
            mMap->map_Map[newRow+_dRow][newCol+_dCol] = 2;//把路变成箱子元素
            mRole->MoveRole(_dRow,_dCol);
        }
        else if (mMap->map_Map[newRow+_dRow][newCol+_dCol] == 3)//判断箱子前方是否洞
        {
            mMap->map_Map[newRow][newCol] = 0;//把箱子变成路元素
            mMap->map_Map[newRow+_dRow][newCol+_dCol] = 4;//把洞变成进洞元素
            mRole->MoveRole(_dRow,_dCol);
        }
    }
    else if (mMap->map_Map[newRow][newCol] == 4) //判断前方是否进洞元素
    {
        if (mMap->map_Map[newRow+_dRow][newCol+_dCol] == 0)//判断进洞前方是否路
        {
            mMap->map_Map[newRow][newCol] = 3;//把进洞变成洞元素
            mMap->map_Map[newRow+_dRow][newCol+_dCol] = 2;//把路变成箱子元素
            mRole->MoveRole(_dRow,_dCol);
        }
    }
    else//否则进行角色移动
    {
        mRole->MoveRole(_dRow,_dCol);
    }

}

        判断是否胜利规则,则是用了扫描整个二维数组是否有箱子元素,如果没有则为胜利,反之则还未结束。

//判断是否胜利
void Widget::IsWin(void)
{
    int temp = 0;
    for(int i = 0;i < mMap->map_Row;i++)
    {
        for (int j = 0; j < mMap->map_Col; j++)
        {
            if (mMap->map_Map[i][j] == 3)//如果有洞元素。怎证明游戏还没有结束
            {
                temp++;
            }
        }
    }
    if (temp == 0)//游戏结束
    {
        // 创建一个消息框
        QMessageBox msgBox;
        msgBox.setWindowTitle("恭喜过关");
        msgBox.setText("请选择选项");

        // 添加确定和取消按钮
        msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);

        // 设置中文文本
        msgBox.setButtonText(QMessageBox::Ok,"下一关!");
        msgBox.setButtonText(QMessageBox::Cancel,"重玩本关");

        // 显示消息框并获取按钮点击结果
        int ret = msgBox.exec();
        if (ret == QMessageBox::Ok)
        {
            // 点击了确定按钮
            // 执行相应的操作
           // return;
        }
        else if (ret == QMessageBox::Cancel) {
            // 点击了取消按钮
            // 执行相应的操作
           // return;
        }
    }
    else//游戏继续
    {

    }
}

总结

        回看整个项目实现过程,其实难度不大,但一些想法和实现筹备是有一定门口的,所有这就凸显出教程的意义,可以给你灵感,快速上手一个项目。回到项目本身,贴出的代码还有没有实现关卡的级别选择,这时可以创建一个三维数组,储存2D地图二维数组,还有一些细节上可以处理。(本项目用到的资源和代码都在链接里,有需要可以下载,如何觉得还不错的话,记得点个赞噢)资料icon-default.png?t=N7T8https://download.csdn.net/download/angelxiaolei/88584631?spm=1001.2014.3001.5503

  • 25
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值