QT实现2048小游戏

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/afterward___/article/details/46375459

QT环境:QT5.2.0,Qt Creator3.0.0

1.自定义方块类

class Square : public QGraphicsItem
{
public:
    explicit Square(QPoint pos,QString text,QString background_color);
    QString getText() {return text;}
    void    updatePos(QPoint pos);
    void    updateText(QString text,QString background_color);
    void    updateBox(QPoint pos,QString text,QString background_color);
    enum {Type = UserType + 1};
    int     type() const;
private :
    QRectF  boundingRect() const;
    void    paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    QString text;
    QString color;
};

Square::Square(QPoint pos,QString text,QString background_color) : QGraphicsItem()
{
    setPos(pos);
    this->text = text;
    this->color = background_color;
    setFlag(QGraphicsItem::ItemIsFocusable);
}
int Square::type() const
{
    return Type;
}
QRectF Square::boundingRect() const
{
    int penWidth = 1;
    return QRectF(0-penWidth/2,0-penWidth/2,105+penWidth,105+penWidth);
}
void Square::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    //画背景
    painter->setPen(QColor(color));
    painter->setBrush(QBrush(QColor(color)));
    painter->drawRect(QRect(0,0,105,105));
    //设置字体 字号
    switch(text.length())
    {
    case 1:
        painter->setFont(QFont(QString::fromLocal8Bit("微软雅黑"),50,QFont::Bold));
        break;
    case 2:
        painter->setFont(QFont(QString::fromLocal8Bit("微软雅黑"),40,QFont::Bold));
        break;
    case 3:
        painter->setFont(QFont(QString::fromLocal8Bit("微软雅黑"),35,QFont::Bold));
        break;
    case 4:
        painter->setFont(QFont(QString::fromLocal8Bit("微软雅黑"),30,QFont::Bold));
        break;
    default:
        break;
    }
    //设置字体颜色
    if(text.toInt() == 2 || text.toInt() == 4)
    {
        painter->setPen(QColor("#7c736a"));
    }
    else if(text.toInt() >= 8)
    {
        painter->setPen(QColor("#fff7eb"));
    }
    painter->drawText(QRect(0,0,105,105),Qt::AlignCenter,text);
}
void Square::updatePos(QPoint pos)
{
    setPos(pos);
    update(boundingRect());
}
void Square::updateText(QString text,QString background_color)
{
    this->text = text;
    this->color = background_color;
    update(boundingRect());
}
void Square::updateBox(QPoint pos,QString text,QString background_color)
{
    this->text = text;
    this->color = background_color;
    setPos(pos);
    update(boundingRect());
}

2.自定义视图类

class GameView : public QGraphicsView
{
    Q_OBJECT
public:
    explicit GameView();
    ~GameView();
private:
    QGraphicsScene *g_scene;
    QMap<qreal,QString> colorBox;
    void    createGrid();
    void    createColorBox();
    void    startGame();
    void    restartGame();
    bool    upMerge();
    bool    downMerge();
    bool    leftMerge();
    bool    rightMerge();
    bool    newSquare();
    void    countEmpty(QList<QPair<int,int> > &empty_index);
    bool    checkSucceeded();
    bool    checkFinished();
    void    keyPressEvent(QKeyEvent * event);
    void    drawBackground(QPainter * painter, const QRectF & rect);
public slots:
};
GameView::GameView() : QGraphicsView()
{
    g_scene = new QGraphicsScene();
    g_scene->setSceneRect(0,0,500,500);
    setScene(g_scene);
    setCacheMode(QGraphicsView::CacheBackground);
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    createGrid();
    createColorBox();
    startGame();
}
GameView::~GameView()
{
}
void GameView::createGrid()
{
    int penWidth = 16;
    QPen pen(QBrush(Qt::SolidPattern),penWidth,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin);
    pen.setColor(QColor("#b8af9e"));
    for(int i = 0;i < 5;i ++)
    {
       g_scene->addLine(i*(105 + penWidth)+penWidth/2,0,i*(105 + penWidth)+penWidth/2,500,pen);
    }
    for(int j = 0;j < 5;j ++)
    {
        g_scene->addLine(0,j*(105 + penWidth)+penWidth/2,500,j*(105 + penWidth)+penWidth/2,pen);
    }
}
 void GameView::createColorBox()
 {
     colorBox.insert(0,tr("#ccc0b2"));
     colorBox.insert(2,tr("#eee4da"));
     colorBox.insert(4,tr("#ece0c8"));
     colorBox.insert(8,tr("#f2b179"));
     colorBox.insert(16,tr("#f59563"));
     colorBox.insert(32,tr("#f57c5f"));
     colorBox.insert(64,tr("#f65d38"));
     colorBox.insert(128,tr("#edc171"));
     colorBox.insert(256,tr("#edcc61"));
     colorBox.insert(512,tr("#ecc850"));
     colorBox.insert(1024,tr("#edc53f"));
     colorBox.insert(2048,tr("#efc4ef"));
 }
 void GameView::startGame()
 {
     int index1,index2;
     int num1,num2;
     //随机生成位置(16个方格,0~15编号)
     index1 = qrand()%16;
     index2 = qrand()%16;
     while(index2 == index1)
     {
         index2 = qrand()%16;
     }
     //随机生成2或4(随机生成0,1,则0代表2,1代表4)
     num1 = qrand()%2==0 ? 2 : 4;
     num2 = qrand()%2==0 ? 2 : 4;
     QPoint pos1((index1%4)*(105+16)+16,(index1/4)*(105+16)+16);
     QPoint pos2((index2%4)*(105+16)+16,(index2/4)*(105+16)+16);
     g_scene->addItem(new Square(pos1,QString::number(num1),colorBox.value(num1)));
     g_scene->addItem(new Square(pos2,QString::number(num2),colorBox.value(num2)));
 }
 void GameView::restartGame()
 {
     QList<QGraphicsItem*> list = scene()->items(0,0,500,500,Qt::IntersectsItemShape,Qt::AscendingOrder);
     foreach(QGraphicsItem *item,list)
     {
         scene()->removeItem(item);
         delete item;
         item = NULL;
     }
     createGrid();
     startGame();
 }
 bool GameView::upMerge()
 {
     bool can_move = false;
     for(int i = 0;i < 4;i ++)
         for(int j = 0;j < 4;j ++)
         {
             QList<QGraphicsItem*> current = scene()->items(i*(105+16)+16,j*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             if(current.count()<=0)
             {
                 continue;
             }
             Square *c_square = qgraphicsitem_cast<Square*>(current[0]);
             for(int k = j + 1;k < 4;k ++)
             {
                 QList<QGraphicsItem*> next = scene()->items(i*(105+16)+16,k*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
                 if(next.count()<=0)
                 {
                     continue;
                 }
                 Square *n_square = qgraphicsitem_cast<Square*>(next[0]);
                 if(n_square->getText() == c_square->getText())
                 {
                     int num = c_square->getText().toInt()*2;
                     c_square->updateText(QString::number(num),colorBox.value(num));
                     scene()->removeItem(n_square);
                     delete n_square;
                     n_square = NULL;
                     can_move = true;
                 }
                 break;
             }
         }
     for(int i = 0;i < 4;i ++)
     {
         int empty_count = 0;
         for(int j = 0;j < 4;j ++)
         {
             QList<QGraphicsItem*> current = scene()->items(i*(105+16)+16,j*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             if(current.count()<=0)
             {
                 empty_count ++;
                 continue;
             }
             Square *square = qgraphicsitem_cast<Square*>(current[0]);
             square->updatePos(QPoint(square->pos().x(),square->pos().y()-empty_count*(105+16)));
             if(empty_count > 0)
             {
                 can_move = true;
             }
         }
     }
     viewport()->update();
     return can_move;
 }
 bool GameView::downMerge()
 {
     bool can_move = false;
     for(int i = 0;i <= 3;i ++)
         for(int j = 3;j >= 0;j --)
         {
             QList<QGraphicsItem*> current = scene()->items(i*(105+16)+16,j*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             if(current.count()<=0)
             {
                 continue;
             }
             Square *c_square = qgraphicsitem_cast<Square*>(current[0]);
             for(int k = j - 1;k >= 0;k --)
             {
                 QList<QGraphicsItem*> next = scene()->items(i*(105+16)+16,k*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
                 if(next.count()<=0)
                 {
                     continue;
                 }
                 Square *n_square = qgraphicsitem_cast<Square*>(next[0]);
                 if(n_square->getText() == c_square->getText())
                 {
                     int num = c_square->getText().toInt()*2;
                     c_square->updateText(QString::number(num),colorBox.value(num));
                     scene()->removeItem(n_square);
                     delete n_square;
                     n_square = NULL;
                     can_move = true;
                 }
                 break;
             }
         }
     for(int i = 0;i < 4;i ++)
     {
         int empty_count = 0;
         for(int j = 3;j >= 0;j --)
         {
             QList<QGraphicsItem*> current = scene()->items(i*(105+16)+16,j*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             if(current.count()<=0)
             {
                 empty_count ++;
                 continue;
             }
             Square *square = qgraphicsitem_cast<Square*>(current[0]);
             square->updatePos(QPoint(square->pos().x(),square->pos().y()+empty_count*(105+16)));
             if(empty_count>0)
             {
                 can_move = true;
             }
         }
     }
     viewport()->update();
     return can_move;
 }
 bool GameView::leftMerge()
 {
     bool can_move = false;
     for(int i = 0;i < 4;i ++)
         for(int j = 0; j < 4;j ++)
         {
             QList<QGraphicsItem*> current = scene()->items(j*(105+16)+16,i*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             if(current.count()<=0)
             {
                 continue;
             }
             Square *c_square = qgraphicsitem_cast<Square*>(current[0]);
             for(int k = j+1;k < 4;k ++)
             {
                 QList<QGraphicsItem*> next = scene()->items(k*(105+16)+16,i*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
                 if(next.count()<=0)
                 {
                     continue;
                 }
                 Square *n_square = qgraphicsitem_cast<Square*>(next[0]);
                 if(c_square->getText() == n_square->getText())
                 {
                     int num = c_square->getText().toInt()*2;
                     c_square->updateText(QString::number(num),colorBox.value(num));
                     scene()->removeItem(n_square);
                     delete n_square;
                     n_square = NULL;
                     can_move = true;
                 }
                 break;
             }
         }
     for(int i = 0;i < 4;i ++)
     {
         int empty_count = 0;
         for(int j = 0;j < 4;j ++)
         {
             QList<QGraphicsItem*> current = scene()->items(j*(105+16)+16,i*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             if(current.count()<=0)
             {
                 empty_count ++;
                 continue;
             }
             Square *square = qgraphicsitem_cast<Square*>(current[0]);
             square->updatePos(QPoint(square->pos().x()-empty_count*(105+16),square->pos().y()));
             if(empty_count>0)
             {
                 can_move = true;
             }
         }
     }
     viewport()->update();
     return can_move;
 }
 bool GameView::rightMerge()
 {
     bool can_move = false;
     for(int i = 0;i < 4;i ++)
         for(int j = 3; j>= 0;j --)
         {
             QList<QGraphicsItem*> current = scene()->items(j*(105+16)+16,i*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             if(current.count()<=0)
             {
                 continue;
             }
             Square *c_square = qgraphicsitem_cast<Square*>(current[0]);
             for(int k = j-1;k >= 0;k --)
             {
                 QList<QGraphicsItem*> next = scene()->items(k*(105+16)+16,i*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
                 if(next.count()<=0)
                 {
                     continue;
                 }
                 Square *n_square = qgraphicsitem_cast<Square*>(next[0]);
                 if(c_square->getText() == n_square->getText())
                 {
                     int num = c_square->getText().toInt()*2;
                     c_square->updateText(QString::number(num),colorBox.value(num));
                     scene()->removeItem(n_square);
                     delete n_square;
                     n_square = NULL;
                     can_move = true;
                 }
                 break;
             }
         }
     for(int i = 0;i < 4;i ++)
     {
         int empty_count = 0;
         for(int j = 3;j >= 0;j --)
         {
             QList<QGraphicsItem*> current = scene()->items(j*(105+16)+16,i*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             if(current.count()<=0)
             {
                 empty_count ++;
                 continue;
             }
             Square *square = qgraphicsitem_cast<Square*>(current[0]);
             square->updatePos(QPoint(square->pos().x()+empty_count*(105+16),square->pos().y()));
             if(empty_count>0)
             {
                 can_move = true;
             }
         }
     }
     viewport()->update();
     return can_move;
 }
 bool GameView::newSquare()
 {
     QList<QPair<int,int> > empty_index;
     countEmpty(empty_index);
     int num = qrand()%2==0 ? 2 : 4;
     int index = qrand()%empty_index.count();
     QPoint pos(empty_index[index].first*(105+16)+16,empty_index[index].second*(105+16)+16);
     g_scene->addItem(new Square(pos,QString::number(num),colorBox.value(num)));
     countEmpty(empty_index);
     if(empty_index.count() <= 0)
     {
         if(checkFinished())       //添加新块,检查是否Game over
         {
             return false;
         }
     }
     return true;
 }
 void GameView::countEmpty(QList<QPair<int,int> > &empty_index)
 {
     empty_index.clear();
     for(int i = 0;i < 4;i ++)      //行号
     {
         for(int j = 0;j < 4;j ++)  //列号
         {
             QList<QGraphicsItem*> list = scene()->items(i*(105+16)+16,j*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             if(list.count() <= 0)
             {
                 empty_index.append(qMakePair(i,j));
             }
         }
     }
 }
 bool GameView::checkSucceeded()
 {
     for(int i = 0;i < 4;i ++)
         for(int j = 0;j < 4;j ++)
         {
             QList<QGraphicsItem*> list = scene()->items(i*(105+16)+16,j*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             if(list.count() >= 1)
             {
                 Square *square = qgraphicsitem_cast<Square*>(list[0]);
                 if(square->getText().toInt() == 2048)
                 {
                     QMessageBox::information(this,QStringLiteral("好消息"),QStringLiteral("恭喜完成,太厉害啦!"),QMessageBox::Ok);
                     return true;
                 }
             }
         }
     return false;
 }
 bool GameView::checkFinished()
 {
     QList<QGraphicsItem*> current;
     QList<QGraphicsItem*> next;
     Square *c_square;
     Square *n_square;
     for(int i = 0;i < 4;i ++)
         for(int j = 0;j < 3;j ++)
         {
             current.clear();
             next.clear();
             current = scene()->items(i*(105+16)+16,j*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             next = scene()->items(i*(105+16)+16,(j+1)*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             c_square = qgraphicsitem_cast<Square*>(current[0]);
             n_square = qgraphicsitem_cast<Square*>(next[0]);
             if(c_square->getText() == n_square->getText())
             {
                 return false;
             }
             current.clear();
             next.clear();
             current = scene()->items(j*(105+16)+16,i*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             next = scene()->items((j+1)*(105+16)+16,i*(105+16)+16,105,105,Qt::IntersectsItemShape,Qt::AscendingOrder);
             c_square = qgraphicsitem_cast<Square*>(current[0]);
             n_square = qgraphicsitem_cast<Square*>(next[0]);
             if(c_square->getText() == n_square->getText())
             {
                 return false;
             }
         }
     QMessageBox::information(this,QStringLiteral("游戏结束"),QStringLiteral("游戏结束..."),QMessageBox::Ok);
     return true;
 }
 void GameView::keyPressEvent(QKeyEvent * event)
 {
     switch(event->key())
     {
     case Qt::Key_Up:
         if(upMerge())
         {
             if(checkSucceeded() || !newSquare())
             {
                 restartGame();
             }
         }
         break;
     case Qt::Key_Down:
         if(downMerge())
         {
             if(checkSucceeded() || !newSquare())
             {
                 restartGame();
             }
         }
         break;
     case Qt::Key_Left:
         if(leftMerge())
         {
             if(checkSucceeded() || !newSquare())
             {
                 restartGame();
             }
         }
         break;
     case Qt::Key_Right:
         if(rightMerge())
         {
             if(checkSucceeded() || !newSquare())
             {
                 restartGame();
             }
         }
         break;
     default:
         QGraphicsView::keyPressEvent(event);
         break;
     }
 }
 void GameView::drawBackground(QPainter * painter, const QRectF & rect)
 {
     painter->setBrush(QBrush(QColor("#ccc0b2")));
     painter->drawRect(QRect(sceneRect().x(),sceneRect().y(),sceneRect().width(),sceneRect().height()));
 }



最后剩下的就是把view显示到mainwindow上:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowTitle(tr("2048"));
    setIconSize(QSize(48,48));
    setFixedSize(542,542);
    setWindowIcon(QIcon(tr("://resources/window_ico_48.png")));
    ui->center->addWidget(new GameView());
}

总结:

代码中有许多不完善的地方,比如方块合并没有特效、没有移动轨迹;新方块的出现太突兀和随机;合并算法比较累赘;程序逻辑不够清晰。甚至存在许多没有发现的错误。不管怎样,作为代码小菜鸟算是抛砖引玉了,请给位大牛指教!!!


附上效果图一张:


展开阅读全文

没有更多推荐了,返回首页