这个程序由于我中间丢失过代码,所以构思稍微有点混乱,算法和主体部分放在了game类中实现。
数据保存,只存了分数,并且也为做优化,所以有瑕疵。
总体分为初始界面,游戏界面,数据保存三块。不多说上代码:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include "game.h"
#include "QPushButton"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
game* G;
QPushButton* startbutton;
QPushButton* closebutton;
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
//按钮的槽函数
void start_clicked();
void close_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
startbutton =new QPushButton(this);
startbutton->setText("STARTGAME");
startbutton->move(150,100);
startbutton->setFlat(true);//就是这句实现按钮透明的效果。
closebutton =new QPushButton(this);
closebutton->setText("EXITGAME");
closebutton->move(150,150);
closebutton->setFlat(true);//就是这句实现按钮透明的效果。
connect(startbutton,SIGNAL(clicked()),this,SLOT(start_clicked()));
connect(closebutton,SIGNAL(clicked()),this,SLOT(close_clicked()));
//setStyleSheet("QWidget{border-image: url(:/new/prefix1/2048.jpg);}");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::start_clicked()
{
G=new game(this);
G->resize(500,500);
G->show();
}
void MainWindow::close_clicked()
{
close();
}
这里用纯代码编写,有点复杂,在移动控件时比较复杂,建议大家使用代码与画布的联合使用,会比较容易。
代码与算法主体GAME:
#ifndef GAME_H
#define GAME_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "datasave.h"
class game : public QMainWindow
{
Q_OBJECT
QLCDNumber* steplcd;
QLCDNumber* scorelcd;
QLCDNumber* maxscorelcd;
QLabel* maxscorelabel;
QLabel* msg;
datasave* data;
public:
explicit game(QWidget *parent = 0);
~game(void);
//分数容器,用来排名
std::vector grade;
//开始游戏
void newgame();
//初始化表格
void setpane();
//判断棋盘中空格个数
int space_num();
//随机出棋盘中两个2
void srand_twonew();
//初始化Label的值
void setLabel(void);
//放置label的位置
void setposlabel(void);
void upmove(); //上移
void downmove(); //下移
void leftmove(); //左移
void rightmove(); //右移
void keyPressEvent(QKeyEvent *event);
void upremoveblank();
void downremoveblank();
void leftremoveblank();
void rightremoveblank();
bool testup(); //能否上移测试
bool testdown(); //能否上移测试
bool testright(); //能否上移测试
bool testleft(); //能否上移测试
int panemax(); //棋盘最大数
void sumscore(); //总分数
bool ifwin(); //判断是否胜利
bool ifGameOver(); //判断是否游戏结束
void update(const int& t);
//设置数字背景色,根据数字不同
void set_back(int i,int j);
//获取炸弹,并且将背景设置为炸弹,添加炸弹按钮
void get_boom(void);
//求最大分数
int maxscore(void);
private:
int pane[4][4];
QHash labelHash;
QGridLayout* layout;
QLabel* label[16];
QWidget * widget;
QPushButton* boombutton;
int stepcount;
int score;
public slots:
void set_boom();
};
#endif // GAME_H
可以看出头文件就很复杂,因为每一个控件都是用代码添加,所以比较繁琐。
#include "game.h"
#include
#include
game::game(QWidget *parent) :
QMainWindow(parent)
{
data=new datasave;
data->load(grade);
// qDebug("-----grade:%d",grade.size());
layout=new QGridLayout;
widget=new QWidget(this);
steplcd=new QLCDNumber(this);
scorelcd=new QLCDNumber(this);
maxscorelcd=new QLCDNumber(this);
setStyleSheet("QMainWindow{border-image: url(:/new/prefix1/1111.jpg);}");
QLabel* stepnum=new QLabel(this);
QLabel* scorenum=new QLabel(this);
maxscorelabel=new QLabel(this);
boombutton=new QPushButton(this);
boombutton->hide();
msg=new QLabel(this);
msg->move(10,40);
msg->hide();
maxscorelabel->setText("MAX:");
stepnum->setText("STEP:");
scorenum->setText("SCORE:");
maxscorelabel->move(100,30);
stepnum->move(260,30);
scorenum->move(260,60);
stepcount=0;
score=0;
maxscorelcd->move(150,30);
steplcd->move(310,30);
scorelcd->move(310,60);
newgame();
stepcount=0;
score=0;
}
game::~game()
{
data->save(grade);
delete data;
}
//初始化表格
void game::setpane()
{
QTime time;
time = QTime::currentTime();
qsrand(time.msec()+time.second()*1000);
for(int i=0;i<=3;i++) //初始化棋盘
for(int j=0;j<=3;j++)
{
pane[i][j]=0;
}
int m=qrand()%4;
int n=qrand()%4;
int b=qrand()%4;
int q=qrand()%4;
pane[m][n]=pane[b][q]=2;
}
//判断棋盘中空格个数
int game::space_num()
{
int num=0;
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(pane[i][j]==0)
{
num++;
}
}
}
return num;
}
//随机出棋盘中两个2
void game::srand_twonew()
{
QTime time;
time = QTime::currentTime();
qsrand(time.msec()+time.second()*1000);
if(space_num()>=2)
{
int count=2;
while(count>0)
{
int m=qrand()%4;
int n=qrand()%4;
if(pane[m][n]==0)
{
pane[m][n]=2;
count--;
}
}
}
else if(space_num()==1)
{
int num=1;
while(num>0)
{
int m=qrand()%4;
int n=qrand()%4;
if(pane[m][n]==0)
{
pane[m][n]=2;
num--;
}
}
}
}
//初始化Label的值
void game::setLabel(void)
{
for(int i=0;i<16;i++)
{
label[i]=new QLabel;
labelHash.insert(i,label[i]);
}
}
//放置label的位置
void game::setposlabel(void)
{
for(int i=0;i<16;i++)
{
labelHash.value(i)->setFrameShape(QLabel::Box);
labelHash.value(i)->setText(" ");
layout->addWidget(labelHash.value(i),i/4,i%4,1,1);
}
layout->setSpacing(4);
widget->setLayout(layout);
widget->resize(300,300);
widget->move(115,90);
}
//开始游戏
void game::newgame()
{
setpane();
setLabel();
setposlabel();
//ui->pushButton->close();
update(0);
}
//上移
void game::upmove()
{
for(int j=0;j<4;j++){//每一列
for(int i=0;i<3;i++){
if(pane[i][j]==pane[i+1][j]){
pane[i][j]=pane[i][j]+pane[i+1][j];
pane[i+1][j]=0;
//移除空格
upremoveblank();
}
}
}
}
//下移
void game::downmove()
{
for(int j=0;j<4;j++){//每一列
for(int i=3;i>=1;i--){
if(pane[i][j]==pane[i-1][j]){
pane[i][j]=pane[i][j]+pane[i-1][j];
pane[i-1][j]=0;
//移除空格
downremoveblank();
}
}
}
}
//左移
void game::leftmove()
{
for(int i = 0;i < 4;i++){
for(int j = 0;j<3;j++){
if(pane[i][j]==pane[i][j+1]){
pane[i][j]+=pane[i][j+1];
pane[i][j+1]=0;
leftremoveblank();
}
}
}
}
//右移
void game::rightmove()
{
for(int i=0;i<4;i++){
for(int j=3;j >= 1;j--){
if(pane[i][j]==pane[i][j-1]){
pane[i][j]+=pane[i][j-1];
pane[i][j-1]=0;
rightremoveblank();
}
}
}
}
void game::keyPressEvent(QKeyEvent *event)
{
if(!ifGameOver())
{
msg->setText("Game Over!");
msg->show();
return;
}
switch (event->key()) {
case Qt::Key_W:
// get_boom();
if(!testup()) return;
upremoveblank();
upmove();
sumscore();
srand_twonew();
stepcount++;
update(stepcount);
break;
case Qt::Key_S:
if(!testdown()) return;
downremoveblank();
downmove();
sumscore();
srand_twonew();
stepcount++;
update(stepcount);
break;
case Qt::Key_A:
if(!testleft()) return;
leftremoveblank();
leftmove();
sumscore();
srand_twonew();
stepcount++;
update(stepcount);
break;
case Qt::Key_D:
if(!testright()) return;
rightremoveblank();
rightmove();
sumscore();
srand_twonew();
stepcount++;
update(stepcount);
break;
default:
break;
}
}
void game::upremoveblank()
{
for(int j=0;j<4;j++){
int k = 0;
for(int i=0;i<4;i++){
if(pane[i][j] != 0)
{
pane[k++][j] = pane[i][j];
}
}
while(k<4)
{
pane[k][j] = 0;
k++;
}
}
}
void game::downremoveblank()
{ for(int j=0;j<4;j++){
int k = 3;
for(int i=3;i>=0;i--){
if(pane[i][j] != 0)
pane[k--][j] = pane[i][j];
}
while(k>=0)
{
pane[k][j] = 0;
k--;
}
}
}
void game::leftremoveblank()
{
for(int i=0;i<4;i++){
int k = 0;
for(int j=0;j<4;j++){
if(pane[i][j] != 0)
pane[i][k++] = pane[i][j];
}
while(k<4)
{
pane[i][k] = 0;
k++;
}
}
}
void game::rightremoveblank()
{
for(int i=0;i<4;i++){
int k = 3;
for(int j=3;j>=0;j--){
if(pane[i][j] != 0)
pane[i][k--] = pane[i][j];
}
while(k>=0)
{
pane[i][k] = 0;
k--;
}
}
}
//能否上移测试
bool game::testup()
{
for(int j=0;j<=3;j++)
for(int i=0;i<3;i++)
{
if(pane[i][j] == pane[i+1][j] || pane[i][j] == 0)
{
return true;
}
}
return false;
}
//能否下移测试
bool game::testdown()
{
for(int j=0;j<=3;j++)
for(int i=3;i>0;i--)
{
if(pane[i][j] == pane[i-1][j] || pane[i][j] == 0)
{
return true;
}
}
return false;
}
//能否右移测试
bool game::testright()
{
for(int i=0;i<=3;i++)
for(int j=3;j>0;j--)
{
if(pane[i][j] == pane[i][j-1] || pane[i][j] == 0)
{
return true;
}
}
return false;
}
//能否左移测试
bool game::testleft()
{
for(int i=0;i<=3;i++)
for(int j=0;j<3;j++)
{
if(pane[i][j] == pane[i][j+1] || pane[i][j] == 0)
{
return true;
}
}
return false;
}
//棋盘最大数
int game::panemax()
{
int max=0;
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(pane[i][j]>max)
{
max=pane[i][j];
}
}
}
return max;
}
//总分数
void game::sumscore()
{
score+=panemax();
}
//判断是否胜利
bool game::ifwin()
{
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(pane[i][j]==2048)
{
return true;
}
}
}
return false;
}
//判断是否游戏结束
bool game::ifGameOver()
{
if((testup()+testdown()+testright()+testleft())==0)
{
return false;
}
return true;
}
void game::update(const int& t)
{
for(int i = 0 ; i < 4 ; i++)
{
for(int j = 0; j < 4; j++)
{
int p = i*4+j;
if(pane[i][j])
{
labelHash.value(p)->setText(QString::number(pane[i][j]));
}
else
{
labelHash.value(p)->setText(" ");
}
QFont ftt;
ftt.setPointSize(24);
labelHash.value(p)->setFont(ftt);
QPalette pa;
pa.setColor(QPalette::WindowText,Qt::white);
labelHash.value(p)->setPalette(pa);
labelHash.value(p)->setAlignment(Qt::AlignCenter);
set_back(i,j);
//labelHash.value(p)->setStyleSheet("background-color: rgb(170, 255, 255);");
}
steplcd->display(QString::number(stepcount));
scorelcd->display(QString::number(score));
maxscorelcd->display((QString::number(maxscore())));
grade.push_back(maxscore());
}
}
void game::set_back(int i,int j)
{
int p=i*4+j;
switch(pane[i][j])
{
case 0: labelHash.value(p)->setStyleSheet("background-color: rgb(97, 0, 0);");break;
case 2: labelHash.value(p)->setStyleSheet("background-color: rgb(100, 170, 127);");break;
case 4: labelHash.value(p)->setStyleSheet("background-color: rgb(255, 100, 127);");break;
case 8: labelHash.value(p)->setStyleSheet("background-color: rgb(85, 170, 0);");break;
case 16:labelHash.value(p)->setStyleSheet("background-color: rgb(170, 85, 255);");break;
//border-image: url(:/new/prefix1/1024.jpg);background-color: rgb(170, 85, 255);
case 32: labelHash.value(p)->setStyleSheet("background-color: rgb(170, 85, 255);");break;
case 64: labelHash.value(p)->setStyleSheet("background-color: rgb(85, 270, 0);");break;
case 128: labelHash.value(p)->setStyleSheet("background-color: rgb(170, 85, 255);"); break;
case 256: labelHash.value(p)->setStyleSheet("border-image: url(:/new/prefix1/1024.jpg)"); get_boom(); break;
case 512: labelHash.value(p)->setStyleSheet("background-color: rgb(85, 170, 0);");;break;
case 1024: labelHash.value(p)->setStyleSheet("background-color: rgb(85, 170, 0);");break;
case 2048: labelHash.value(p)->setStyleSheet("background-color: rgb(255, 255, 127);");break;
case 4096: labelHash.value(p)->setStyleSheet("background-color: rgb(97, 0, 0);");break;
case 8192: labelHash.value(p)->setStyleSheet("background-color: rgb(90, 90, 90);");break;
}
}
//获取炸弹,并且将背景设置为炸弹,添加炸弹按钮
void game::get_boom(void)
{
//qDebug("----------");
// boombutton=new QPushButton(this);
boombutton->move(10,10);
boombutton->setText("BOOM");
boombutton->setStyleSheet("background-color: rgb(97, 0, 0);");
connect(boombutton,SIGNAL(clicked()),this,SLOT(set_boom()));
boombutton->show();
}
//按下按钮炸掉炸弹,炸掉自己
void game::set_boom()
{
boombutton->hide();
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(pane[i][j]==256)
{
pane[i][j]=0;
}
}
}
update(score);
}
//求最大分数
int game::maxscore(void)
{
int s=0;
for(unsigned int i=0;iscore)
{
return s;
}
else
{
return score;
}
}
有些地方注释写的不够明白,因为数据丢失,所以我反复写的时候就没给出很详细的注释,set_back部分,是根据数字的不同设置不同的背景色!
炸弹是通过按钮实现的,当出现炸弹时按钮也会出现,可以引爆,最大分数更新稍微有点浪费存储控件,未作出优化,优化方法较为简单,这里就不过多赘述。
#ifndef DATASAVE_H
#define DATASAVE_H
#include
//#include "game.h"
#include
#include
using namespace std;
class datasave : public QObject
{
Q_OBJECT
public:
explicit datasave(QObject *parent = 0);
void load(vector& grade);
void save(vector& grade);
signals:
public slots:
};
#endif // DATASAVE_H
#include "datasave.h"
#include
#include
using namespace std;
datasave::datasave(QObject *parent) :
QObject(parent)
{
}
void datasave::load(vector& grade)
{
ifstream in;
in.open("./score.dat",ios::binary);
int s;
// qDebug("-------------load:%d",grade.size());
while(in.read((char*)&s,sizeof(int)))
{
grade.push_back(s);
}
// qDebug("-------------load:%d",grade.size());
}
void datasave::save(vector& grade)
{
ofstream out;
//qDebug("-------------save:%d",grade.size());
out.open("./score.dat",ios::binary);
for(unsigned int i=0;i
数据读写,就最基础的存储方式。
整个程序比较简单,不过算法方面都是比较成熟的,所以大家可以取其精华,去其糟粕。