使用QT实现2048小游戏


不废话,先看效果

  • 游戏效果
  • 基本原理
    • 通过按键响应函数void keyPressEvent(QKeyEvent *event)实现画面刷新,每次按键后执行操作并且刷新画面。
    • 画面刷新通过改变不同区域的样式表。
    • 游戏的后台逻辑和原理以及代码:控制台版2048
    • qt完整工程:github
    • 主界面类:widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include "game.h"
#include <QWidget>
#include <QKeyEvent>
#include "dialog.h"
#include <QLabel>
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
     Game game;
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();
   void SHOW();//打印到屏幕
public slots:
   void JiXu();//槽函数,继续游戏
   void TuiChu();//槽函数,退出游戏
private:
    void keyPressEvent(QKeyEvent *event);//获取输入并执行相应操作
    QLabel *lab;
    Ui::Widget *ui;
    Dialog *dialog;//定义一个对话框成员

};

#endif // WIDGET_H

  • 主界面cpp文件
#include "widget.h"
#include "ui_widget.h"
#include <QKeyEvent>
#include <QDebug>
#include <QString>
#include "game.h"
#include <QMessageBox>
#include <QLabel>
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setFocus();
    game.Restart();
    this->SHOW();
    /* 设置对话框 */
    dialog =new Dialog(this);
    dialog->setModal(true);//模态窗口模式
    dialog->setWindowTitle("2048");
    dialog->hide();
    lab=new QLabel(dialog);
    lab->move(70,20);
    /*连接信号和槽 */
    connect(dialog,SIGNAL(jixu()),this,SLOT(JiXu()));
    connect(dialog,SIGNAL(tuichu()),this,SLOT(TuiChu()));
}


Widget::~Widget()
{
    delete ui;
}


void Widget::SHOW()
{
    //通过改变不同位置的样式表来显示不同的数字
    for (int i=0;i<4;i++) {
        for (int j=0;j<4;j++) {
            int x=i*4+j;
            QGraphicsView *p=nullptr;
            //选择指针指向位置(第几行第几列)
            switch (x) {
            case 0: p=ui->p1;break;
            case 1: p=ui->p2;break;
            case 2: p=ui->p3;break;
            case 3: p=ui->p4;break;
            case 4: p=ui->p5;break;
            case 5: p=ui->p6;break;
            case 6: p=ui->p7;break;
            case 7: p=ui->p8;break;
            case 8: p=ui->p9;break;
            case 9: p=ui->p10;break;
            case 10: p=ui->p11;break;
            case 11: p=ui->p12;break;
            case 12: p=ui->p13;break;
            case 13: p=ui->p14;break;
            case 14: p=ui->p15;break;
            case 15: p=ui->p16;break;
            default:break;
            }
            //选择显示的数据
            switch(game.BoardList[i][j])
            {
            case 0:p->setStyleSheet("border-image:url(:/img/0.png)");break;
            case 2:p->setStyleSheet("border-image:url(:/img/2.png)");break;
            case 4:p->setStyleSheet("border-image:url(:/img/4.png)");break;
            case 8:p->setStyleSheet("border-image:url(:/img/8.png)");break;
            case 16:p->setStyleSheet("border-image:url(:/img/16.png)");break;
            case 32:p->setStyleSheet("border-image:url(:/img/32.png)");break;
            case 64:p->setStyleSheet("border-image:url(:/img/64.png)");break;
            case 128:p->setStyleSheet("border-image:url(:/img/128.png)");break;
            case 256:p->setStyleSheet("border-image:url(:/img/256.png)");break;
            case 512:p->setStyleSheet("border-image:url(:/img/512.png)");break;
            case 1024:p->setStyleSheet("border-image:url(:/img/1024.png)");break;
            case 2048:p->setStyleSheet("border-image:url(:/img/2048.png)");break;
            default:break;
            }
        }
    }
}

void Widget::JiXu()
{
    game.Restart();
    this->SHOW();
    this->SHOW();
}
void Widget::TuiChu()
{
    this->close();
}

void Widget::keyPressEvent(QKeyEvent *event)
{
    //根据按键执行相应的函数
    if(event->key()==Qt::Key_Escape)
    {
        this->close();
    }
    if(event->key()==Qt::Key_R)
    {

        game.Restart();

    }
    if(event->key()==Qt::Key_Up)
    {
        game.Up();
    }
    if(event->key()==Qt::Key_Left)
    {
        game.Left();
    }
    if(event->key()==Qt::Key_Right)
    {
        game.Right();
    }
    if(event->key()==Qt::Key_Down)
    {
        game.Down();
    }
    if(game.LOSE())
    {

        lab->setText("你输了,是否继续?");
        dialog->show();
     }
    if(game.WIN())
    {
        lab->setText("你赢了,是否继续?");
        dialog->show();
    }
    this->SHOW();
}
  • 游戏输赢后的提示框:dialog.h
#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>

/*
定义一个对话框,游戏输了或者赢了,弹出
*/
namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT
public:
    explicit Dialog(QWidget *parent = nullptr);
    ~Dialog();
signals:
    void jixu();//发送继续游戏信号
    void tuichu();//发送退出游戏信号
private slots:
    void on_pushButton_2_released();
    void on_pushButton_released();
private:
    Ui::Dialog *ui;
};

#endif // DIALOG_H

  • 提示框cpp文件
#include "dialog.h"
#include "ui_dialog.h"
#include "widget.h"
Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::on_pushButton_2_released()
{

    emit this->jixu();
    this->hide();

}

void Dialog::on_pushButton_released()
{

    emit this->tuichu();
    this->hide();


}

  • 游戏后台:game.h
#ifndef GAME_H
#define GAME_H
class Game
{
public:
    int Scroe = 0;//初始分数
    bool ADD = false;//是否添加棋子
    int BoardList[4][4] = {};
    Game();// 构造函数, 初始化一些参数
    bool AddBoard();//添加棋子
    void Up();//上下左右按键事件,都类似,以左按键为母版
    void Down();
    void Right();
    void Left();
    void Restart();//复位
    bool WIN();//判断是否赢了
    bool LOSE();//判断是否输了
};


#endif // GAME_H

  • 游戏后台cpp文件
#include "game.h"
#include <iomanip>
#include <conio.h>
#include <ctime>

Game::Game()
{

}
bool Game::LOSE()
{
    bool lose=true;//标志位
    //出现0,表示还未结束
    for (size_t i = 0; i < 4; i++)
    {
        for (size_t j = 0; j <4; j++)
        {

            if (this->BoardList[i][j] == 0)
            {
                lose = false;
                return false;
            }
        }
    }
    //横竖相邻元素相等未结束
    for (size_t i = 0; i < 4 - 1; i++)
    {
        for (size_t j = 0; j < 4 - 1; j++)
        {
            if (this->BoardList[i][j]== this->BoardList[i][j+1]&& this->BoardList[i][j]!=0)
            {
                return false;
            }
            if (this->BoardList[j][i]== this->BoardList[j+1][i]&& this->BoardList[j][i]!=0)
            {
                lose = false;
                return false;
            }
        }
    }
    if (lose)
    {
        return true;
    }
    return false;
}

bool Game::WIN()
{
    for (size_t i = 0; i <4; i++)
    {
        for (int j = 0; j <4; ++j)
        {
            //出现2048,即为赢
            if (this->BoardList[i][j]==2048)
            {
                return true;
            }

        }
    }
    return false;
}
bool Game::AddBoard()
{
    int choice[] = { 4, 2, 4, 4, 2, 2, 2, 2 };//可以调节2和4出现的频率
    //srand(time(0));
    int temp = (rand() % int((sizeof(choice)/sizeof (choice[0]) - 0))) + 0;
    int p1 = rand() % 4;
    int p2 = rand() % 4;
    while (this->BoardList[p1][p2] != 0)//位置已有数字,重新选取
    {
        p1 = rand() % 4;
        p2 = rand() % 4;
    }
    this->BoardList[p1][p2] = choice[temp];
    this->ADD = false;
    return true;
}

void Game::Up()
{
    for (size_t i = 0; i <4; i++)
    {
        for (size_t t = 0; t <4; t++)
        {
            for (size_t j = 0; j <4 - 1; j++)
            {
                if (this->BoardList[j][i] == 0)
                {
                    if (this->BoardList[j + 1][i]!=0)
                    {
                        this->ADD = true;
                    }
                    auto temp = this->BoardList[j][i];
                    this->BoardList[j][i] = this->BoardList[j + 1][i];
                    this->BoardList[j + 1][i] = temp;
                }
            }
        }
        // 2、合并同类项
        for (size_t j = 0; j < 4 - 1; j++)
        {
            // 2 2 2 2 ->4 0 2 2 ->4 0 4 0
            // 2 2 2 0 -> 4 0 2 0
            if (this->BoardList[j][i] == this->BoardList[j + 1][i])
            {
                if (this->BoardList[j][i]!=0)
                {
                    this->ADD = true;
                }
                this->BoardList[j][i] = this->BoardList[j][i] * 2;
                this->Scroe = this->BoardList[j][i] + this->Scroe;
                this->BoardList[j + 1][i] = 0;
            }
        }
        //3、 再次移动0元素
        for (size_t t = 0; t < 4; t++)
        {
            for (size_t j = 0; j < 4 - 1; j++)
            {
                // 0 2 0 2 -> 2 2 0 0
                if (this->BoardList[j][i] == 0)
                {
                    auto temp = this->BoardList[j][i];
                    this->BoardList[j][i] = this->BoardList[j + 1][i];
                    this->BoardList[j + 1][i] = temp;
                }
            }
        }
    }
    if (this->LOSE() || this->WIN())
    {}
    else
    {
        if (this->ADD)
        {

            this->AddBoard();
            this->ADD = false;
        }
    }
}

void Game::Down()
{
    for (size_t i = 0; i < 4; i++)
    {
        for (size_t t = 4; t>0; t--)
        {
            for (size_t j = 4 - 1; j >0; j--)
            {
                if (this->BoardList[j][i] == 0)
                {
                    if (this->BoardList[j - 1][i] != 0)
                    {
                        this->ADD = true;
                    }
                    auto temp = this->BoardList[j][i];
                    this->BoardList[j][i] = this->BoardList[j - 1][i];
                    this->BoardList[j - 1][i] = temp;
                }
            }
        }
        // 2、合并同类项
        for (size_t j =4 - 1; j>0; j--)
        {
            // 2 2 2 2 ->4 0 2 2 ->4 0 4 0
            // 2 2 2 0 -> 4 0 2 0
            if (this->BoardList[j][i] == this->BoardList[j - 1][i])
            {
                if (this->BoardList[j][i] != 0)
                {
                    this->ADD = true;
                }
                this->BoardList[j][i] = this->BoardList[j][i] * 2;
                this->Scroe = this->BoardList[j][i] + this->Scroe;
                this->BoardList[j - 1][i] = 0;
            }
        }
        //3、 再次移动0元素
        for (size_t t =4; t >0; t--)
        {
            for (size_t j =4 - 1; j >0; j--)
            {
                // 0 2 0 2 -> 2 2 0 0
                if (this->BoardList[j][i] == 0)
                {
                    auto temp = this->BoardList[j][i];
                    this->BoardList[j][i] = this->BoardList[j - 1][i];
                    this->BoardList[j - 1][i] = temp;
                }
            }
        }
    }
    if (this->LOSE() || this->WIN())
    {}
    else
    {
        if (this->ADD)
        {

            this->AddBoard();
            this->ADD = false;
        }
    }
}

void Game::Left()
{
    for (size_t j= 0; j <4; j++)
    {
        //1、先移动每行0元素(出现0就交换),最多交换size(this->BoardList)次
        for (size_t t = 0; t <4; t++)
        {
            for (size_t i = 0; i <4 - 1; i++)
            {
                // 0 2 0 2 ->2 0 2 0
                if (this->BoardList[j][i] == 0)
                {
                    // 发生了移动,添加棋子标志位置真
                    if (this->BoardList[j][i + 1]!=0)
                    {
                        this->ADD = true;
                    }
                    auto temp = this->BoardList[j][i];
                    this->BoardList[j][i] = this->BoardList[j][i + 1];
                    this->BoardList[j][i + 1] = temp;
                }
            }
        }
        // 2、合并同类项
        for (size_t i = 0; i <4 - 1; i++)
        {
            // 2 2 2 2 ->4 0 2 2 ->4 0 4 0
            // 2 2 2 0 -> 4 0 2 0
            if (this->BoardList[j][i]== this->BoardList[j][i+1])
            {
                // 发生了合并,添加棋子标志位置真
                if (this->BoardList[j][i]!=0)
                {
                    this->ADD = true;
                }
                this->BoardList[j][i] = this->BoardList[j][i] * 2;
                this->Scroe = this->BoardList[j][i] + this->Scroe;
                this->BoardList[j][i + 1] = 0;
            }
        }
        //3、 再次移动0元素 4 0 2 0 -> 4 2 0 0
        for (size_t t = 0; t < 4; t++)
        {
            for (size_t i = 0; i <4 - 1; i++)
            {
                // 0 2 0 2 -> 2 2 0 0
                if (this->BoardList[j][i] == 0)
                {
                    auto temp = this->BoardList[j][i];
                    this->BoardList[j][i] = this->BoardList[j][i + 1];
                    this->BoardList[j][i + 1] = temp;
                }
            }
        }
    }
    //赢了或者输了就不再添加
    if (this->LOSE()||this->WIN())
    {}
    else
    {
        if (this->ADD)
        {

            this->AddBoard();
            this->ADD = false;
        }
    }
}

void Game::Right()
{
    for (size_t j = 0; j < 4; j++)
    {
        //1、先移动每行0元素
        for (size_t t = 4; t >0;t--)
        {
            for (size_t i =4 - 1; i>0; i--)
            {
                if (this->BoardList[j][i] == 0)
                {
                    if (this->BoardList[j][i - 1]!=0)
                    {
                        this->ADD = true;
                    }
                    auto temp = this->BoardList[j][i];
                    this->BoardList[j][i] = this->BoardList[j][i - 1];
                    this->BoardList[j][i - 1] = temp;
                }
            }
        }
        // 2、合并同类项
        for (size_t i =4 - 1; i >0; i--)
        {
            if (this->BoardList[j][i] == this->BoardList[j][i - 1])
            {
                if (this->BoardList[j][i] != 0)
                {
                    this->ADD = true;
                }
                this->BoardList[j][i] = this->BoardList[j][i] * 2;
                this->Scroe = this->BoardList[j][i] + this->Scroe;
                this->BoardList[j][i - 1] = 0;
            }
        }
        //3、 再次移动0元素
        for (size_t t =4; t > 0; t--)
        {
            for (size_t i = 4 - 1; i > 0; i--)
            {
                // 0 2 0 2 -> 2 2 0 0
                if (this->BoardList[j][i] == 0)
                {
                    auto temp = this->BoardList[j][i];
                    this->BoardList[j][i] = this->BoardList[j][i - 1];
                    this->BoardList[j][i - 1] = temp;
                }
            }
        }
    }
    //赢了或者输了就不再添加
    if (this->LOSE() || this->WIN())
    {}
    else
    {
        if (this->ADD)
        {

            this->AddBoard();
            this->ADD = false;
        }
    }
}

void Game::Restart()
{
    this->Scroe = 0;//初始分数
    this->ADD = false;//是否添加棋子
    for (size_t i = 0; i < 4; i++)
    {
        for (size_t j = 0; j < 4; j++)
        {
            this->BoardList[i][j] =0;
        }
    }
    this->AddBoard();
    this->AddBoard();
}


  • 19
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值