Qt实践之2048:

2048的实现,还有很多功能没有加,以后有时间再弄,比起普通的游戏添加了向斜的四个方向滑动的功能

Game_1024_Window.h
#ifndef GAME_1024_WINDOW_H
#define GAME_1024_WINDOW_H

#include <QMainWindow>
#include "QGraphicsView"
#include "gamecontroller.h"

namespace Ui {
class Game_1024_Window;
}

class Game_1024_Window : public QMainWindow
{
    Q_OBJECT

public:
    explicit Game_1024_Window(QWidget *parent = 0);
    void initscene();//初始化场景
    void initbackground();//初始化游戏背景
    ~Game_1024_Window();

private:
    Ui::Game_1024_Window *ui;
    QGraphicsScene *scene;//游戏场景
    QGraphicsView *view;//游戏视图
    void add_bottom_Line();//添加游戏视图的分界线
public:
    GameController *controller;//控制游戏逻辑的类
};
#endif // GAME_1024_WINDOW_H
//gamecontroller.h
#ifndef GAMECONTROLLER_H
#define GAMECONTROLLER_H

#include <QObject>
#include "number_block.h"
#include "QVector"
#include "QPointF"
#include "QMap"
#include "QPropertyAnimation"
#include "QParallelAnimationGroup"
struct change //表示这一次指令游戏滑块的移动方向
{

    change(int a = 0,int b = 0,int c = 0,int d = 0):x1(a),y1(b),x2(c),y2(d){}
    int x1,y1,x2,y2;
};

class GameController : public QObject
{
    Q_OBJECT
    using MyType = QVector<QVector<Number_block*> >;
    using TestType = QVector<QVector<int> >;
public:
    bool slide(QString);//控制数字块的滑动
    bool Gameover();//检测游戏是否已经结束
    void add_item();//增加新的滑块
    explicit GameController(QGraphicsScene*,QObject *parent = 0);
    ~GameController();
protected:
     bool eventFilter(QObject*,QEvent*);
private:
    int N = 4;
    int game_scores;//本次游戏的分数游戏
    bool valuechanged;//用来判定这一次的滑动是否改变了矩阵
    int count;//滑块的数目
    MyType matrix;//存储方块的矩阵
    TestType data;//数字矩阵
    QMap<QString,change> direction;//存储滑动方向
    QGraphicsScene *scene;//游戏场景
    QGraphicsTextItem* scores;//分数文本
    QPropertyAnimation* anim;//动画
    QParallelAnimationGroup group;//存储每一个动画
    void recover();//用来在动画结束后让所有QGraphicsItem保持和data一致
    void handlekeyPressed(QKeyEvent *event);//处理键盘事件
};

#endif // GAMECONTROLLER_H
//Number_block.h
#ifndef NUMBER_BLOCK_H
#define NUMBER_BLOCK_H
#include "QGraphicsObject"

#include "QObject"
#include "QPointF"


class GameController;
class Number_block: /*public QObject, */public QGraphicsObject
{

public:
friend class GameController;

    Number_block(int = 0,qreal x = 0,qreal y = 0);
    ~Number_block();
    void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0)
      Q_DECL_OVERRIDE;
    QRectF boundingRect()  const Q_DECL_OVERRIDE;
private:
    size_t number;//方块的数字
    int get_index(int);//用来获取数字对应2的哪一次幂
};
#endif // NUMBER_BLOCK_H
//gamewindow.cpp
#include "game_1024_window.h"
#include "ui_game_1024_window.h"
#include "QTextStream"
#include"QString"

Game_1024_Window::Game_1024_Window(QWidget *parent) :
    QMainWindow(parent),    ui(new Ui::Game_1024_Window),
    scene(new QGraphicsScene(this)),view(new QGraphicsView(scene,this)),
    controller(new GameController(scene,this))
{
     ui->setupUi(this);
     resize(400,400);
     view->setMinimumSize(350, 350);  //2者设置成一样说明视图尺寸不能再更改
     view->setMaximumSize(300, 300);
     setCentralWidget(view);//将view显示出在GameWindow中央
     view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//取消掉滚动条
     view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
     initscene();
     initbackground();
}

Game_1024_Window::~Game_1024_Window()
{
    delete ui;

   }

 void Game_1024_Window:: initscene()
 {
     scene->setSceneRect(-150,-150,300,300);//设置scene的大小


 }
void Game_1024_Window::initbackground()
{

    scene->setBackgroundBrush(QBrush(Qt::lightGray));//将整个背景bg填充
    //接下来画出四条线
    add_bottom_Line();
}

void Game_1024_Window::add_bottom_Line()
{
    QPen pen = QPen(Qt::white, 5, Qt::SolidLine, Qt::RoundCap);
        for(int i = 0;i!=4;++i)
        {
            int y = -100+50*i;
            scene->addLine(-100,y,100,y,pen);
            scene->addLine(y,-100,y,100,pen);
        }
    scene->addLine(100,-100,100,100,pen);
    scene->addLine(-100,100,100,100,pen);
}
#include "gamecontroller.h"
#include "QGraphicsView"
#include "QKeyEvent"
#include "QSharedPointer"
#include "QPropertyAnimation"
#include "QEventLoop"
#include "time.h"
#include "QDebug"
#include "QTimer"
int N = 4;
 bool inline isgood(int x){return  ((x!=N&&x!=-1)?true:false);}
GameController::GameController(QGraphicsScene *sce,QObject *parent) : QObject(parent),
    matrix( MyType (4)),data(TestType(4)),count(3),game_scores(0),
    scene(sce),scores(new QGraphicsTextItem)
{

     connect(&group,QAbstractAnimation::finished,this,recover);//动画结束后要recover
     scene->addItem(scores);
     scores->setFont(QFont("Times", 20, QFont::Bold));//为文本设置字体
     scores->setPos(50, -160);//分数在场景中出现的位置
     scores->setHtml(tr("<font color = white >%1</font>").arg(game_scores));//设置分数值
    for(int i  = 0;i!=4;++i)
        for(int j = 0;j!=4;++j)
        {
            data[i].push_back(0);
             matrix[i].push_back(0);
        }
    matrix[3][0] = new Number_block(2,-75,75);
    scene->addItem(matrix[3][0]);
    data[3][0] = 2,data[3][1] = 2,data[3][2] = 2;
    matrix[3][1] = new Number_block(2,-25,75);
   scene->addItem(matrix[3][1]);
   matrix[3][2] = new Number_block(2,25,75);
   scene->addItem(matrix[3][2]);


//下面插入方向
     int N = 4;
       direction.insert("up", change(-1, 0, 1, 0) );
        direction.insert( "down", change(1, 0, N - 2, 0));
        direction.insert( "left", change(0,-1 , 0, 1));
        direction.insert( "right", change(0, 1, 0, N-2) );
        direction.insert("leftup", change(-1, -1, 1, 1) );
        direction.insert( "rightdown", change(1, 1, N-2, N-2) );
        direction.insert( "leftdown", change(1, -1, N-2, 1) );
        direction.insert( "rightup", change(-1, 1, 1, N-2) );
        //添加键盘处理
        scene->installEventFilter(this);
}

GameController::~GameController()
{

}

bool GameController:: slide(QString ms)
{
    group.clear();
    int N = 4;
    int de_i = direction[ms].x1,de_j = direction[ms].y1;
    auto beg_row = direction[ms].x2,beg_col = direction[ms].y2;
    auto de_row = (beg_row==N-2) ? -1 : 1,de_col = (beg_col==N-2) ? -1 : 1;
   valuechanged = false;
    TestType isnewvalue(N);
    for ( int i = 0;i!=4;++i)//创建两个数字矩阵
        isnewvalue[i].resize(N);

    for (size_t i = beg_row; isgood(i);i+=de_row)
    for (size_t j = beg_col; isgood(j); j+=de_col)
    {

        bool ismoved = false;
         bool ismerged = false;
        if (!data[i][j])
            continue;//当前数字不存在,直接处理下一个数字
        int temp_i = i, temp_j = j;
        anim = new QPropertyAnimation(matrix[i][j],"pos");
        if (!data[i + de_i][j + de_j])//当前方向没有数字
        {
            ismoved = true;//代表移动过
            valuechanged = true;//数字将会移动,状态改变
            while (isgood(i + de_i) && isgood(j + de_j)&&!data[i + de_i][j + de_j] )
                 i += de_i,j += de_j;
            //  下面实现数字块滑动的效果

            anim->setDuration(250);
            anim->setKeyValueAt(0,QPoint(-75+50*temp_j,-75+50*temp_i));
            anim->setKeyValueAt(0.5,QPoint(-75+50*j,-75+50*i));
           //处理数字的移动
              auto temp = data[i][j];
              data[i ][j] = data[temp_i][temp_j];
              data[temp_i][temp_j] = temp;
        }

        //数字移动后继续进行合并
      if (isgood(i+de_i)&&isgood(j+de_j)&&(data[i][j] ==
                                             data[i + de_i][j + de_j])&&
            !isnewvalue[i+de_i][j+de_j])
        {

           ismerged = true;
            if(!ismoved)//如果数字没有移动过,就要单独设置一个动画
            {
              anim->setDuration(250);
              anim->setKeyValueAt(0,QPoint(-75+50*j,-75+50*i));
            }
            anim->setEndValue(QPoint(-75+50*(j+de_j),-75+50*(i+de_i)));//将数字移动的动画和合并动画设置为一个

             data[i][j] = 0;
            data[i + de_i][j + de_j] *= 2;//数值加倍
            game_scores += data[i+de_i][j+de_j];
            isnewvalue[i + de_i][j + de_j] = 1;//标记为刚刚生成
            --count;//数字个数少1
            valuechanged = true;//数字合并,状态改变

        }

      if(!ismerged)//还没有设置移动终点
      {
          anim->setDuration(anim->duration()*2);//将动画持续时间加倍,保证前后顺序一致
          anim->setEndValue(QPoint(-75+50*j,-75+50*i));
      }
         group.addAnimation(anim);
        i = temp_i, j = temp_j;
    }

    return valuechanged;//返回矩阵状态是否改变过
}

 bool  GameController::eventFilter(QObject* obj,QEvent* event)
 {
     if(event->type()==QEvent::KeyPress)//来自键盘的事件
     {
    handlekeyPressed(static_cast<QKeyEvent*>(event));
         return true;
     }
     else
         return QObject::eventFilter(obj,event);
 }
void GameController::handlekeyPressed(QKeyEvent *event)
{
    //cltr+<-左上,cltr+->右上
    //Alt+<-左下,Alt+->右下

    QString ms;
    if(event->modifiers()==Qt::NoModifier)//不是组合键
    {
    switch(  event->key())
    {
    case Qt::Key_Left: ms = "left";break;
    case Qt::Key_Right: ms ="right";break;
    case Qt::Key_Up:ms = "up";break;
    case Qt::Key_Down:ms = "down"; break;
    }
    }
    else if (event->modifiers()==Qt::ControlModifier)//cltr组合键
        {
        switch(  event->key())
        {
        case Qt::Key_Left: ms = "leftup";break;
        case Qt::Key_Right: ms ="rightup";break;
          }
    }
    else//alt组合键
        {
        switch(  event->key())
        {
        case Qt::Key_Left: ms = "leftdown";break;
        case Qt::Key_Right: ms ="rightdown";break;
        }
    }
    if(!ms.isEmpty())
   {
    slide(ms);//滑动
    group.start();//开始动画
    }
}
void GameController:: recover()
{
       for(int i = 0;i!=4;++i)
           for(int j = 0;j!=4;++j)
           {
               if(!matrix[i][j])
               {
                   if(data[i][j]){
                   matrix[i][j] = new Number_block(data[i][j],-75+50*j,-75+50*i);
                    scene->addItem(matrix[i][j]);
                   }
               }
            else if(!data[i][j])
               {
                  scene->removeItem(matrix[i][j]);
                  delete matrix[i][j];
                  matrix[i][j] = 0;
               }
               else if(data[i][j]!=matrix[i][j]->number)
               {
                   matrix[i][j]->number = data[i][j];
                   matrix[i][j]->setPos(-75+50*j,-75+50*i);
               }
               else
                   matrix[i][j]->setPos(-75+50*j,-75+50*i);
           }
       scene->update();   
       if(valuechanged)//如果确实数字改变了状态,添加动画
       add_item();//在动画结束且矩阵数据复原后添加
       //判断是否结束游戏
       if(valuechanged&&Gameover())//在数字矩阵状态改变的情况下进行判断
       {
           qDebug()<<"gameover\n";
           group.clear();//清除所有动画
           game_scores = 0;//分数清零

           for(int i = 0;i!=4;++i)
               for(int j = 0;j!=4;++j)
               {
                   data[i][j] = 0;
                   scene->removeItem(matrix[i][j]);
                   delete matrix[i][j];
                   matrix[i][j] = 0;
               }
           count = 0;

           add_item();
       }
         scores->setHtml(tr("<font color = white >%1</font>").arg(game_scores));//设置分数值
}
void GameController::add_item()
{
            int x, y;
            srand(time(0));//产生随机数种子
            int n = 0;//随机产生1个数字
            while (count != N*N&&n != 1)
            {
                do{
                    x = rand() % N;
                    y = rand() % N;
                } while (data[x][y]);
                matrix[x][y] = new Number_block((count % 2) ? 2 : 4,-75+50*y,-75+50*x);
                scene->addItem(matrix[x][y]);
                data[x][y] = matrix[x][y]->number;
                ++count;//总个数加1
                ++n;//创建次数加1
            }
}
bool GameController::Gameover()
{
    if(count!=N*N)
        return false;
    for(int i = 0;i!=4;++i)
        for(int j = 0;j!=4;++j)
        {
          if(j<=2&&data[i][j] == data[i][j+1])
              return false;
          if(i<=2&&data[i][j] == data[i+1][j])
              return false;
        }
    return true;
}
#include "number_block.h"
#include "QPainter"
#include "QString"
#include "QObject"
Number_block::Number_block(int num, qreal x, qreal y):number(num)
{
    setPos(x,y);
}

Number_block::~Number_block()
{

}

void Number_block:: paint(QPainter * painter,
                          const QStyleOptionGraphicsItem *, QWidget *)
{

    QColor digitBkg[11] = {QColor::fromRgb(0xEE, 0xE5, 0xDB), QColor::fromRgb(0xEC, 0xE0, 0xC8),
                                QColor::fromRgb(0xF2, 0xAF, 0x78), QColor::fromRgb(0xEE, 0x8A, 0x54),
                                QColor::fromRgb(0xFE, 0x76, 0x5E), QColor::fromRgb(0xE7, 0x58, 0xC),
                                QColor::fromRgb(0xFF, 0x66, 0x66), QColor::fromRgb(0xF1, 0xCF, 0x48),
                                QColor::fromRgb(0xCC, 0x33, 0x33), QColor::fromRgb(0xE3, 0xB9, 0x11),
                                QColor::fromRgb(0xFF, 0x00, 0x00)};//颜色数组

    if(number!=0)//数字不为0
    {
      int index = get_index(number);
       painter->setPen(digitBkg[index]);
       painter->setBrush(QBrush(digitBkg[index]));
       painter->drawRect(boundingRect());
       painter->setFont(QFont("Microsoft YaHei UI",10,QFont::Black));
       painter->setPen(Qt::black);
       painter->drawText(boundingRect(), Qt::AlignCenter, tr("%1").arg(number));
    }
}
QRectF Number_block:: boundingRect()const
{
    return QRect(-20,-20,40,40);
}
int Number_block::get_index(int x)//获取x是2的几次方
{
    int i = -1;
    while(x)
       {
        x = x>>2;
        ++i;
       }

    return i;
}
#include "game_1024_window.h"
#include <QApplication>
#include "QTextStream"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Game_1024_Window w;
    w.show();
    return a.exec();
}

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值