文章目录
- 一、项目简介
- 二、图片和音效资源
- 三、程序设计
- 1. 创建主场景
- 2. 自定义开始按钮
- 3. 创建选择关卡场景
- 4. 创建翻金币场景
- 5. 设置金币及其翻转效果
- 6. 设置关卡的难易程度
一、项目简介
本游戏一共有二十关,你可以从第一关开始接着来,当你完成第一关之后会自动跳到下一关,你还可以直接选择自己想要闯的关卡。进入关卡之后会有一个4*4的网格,里面分布着金币和银币,点击银币它本身和附近的币就会翻面,当网格中只剩金币时,闯关成功。
实现效果:
二、图片和音效资源
链接:https://pan.baidu.com/s/1DyG-INZZVFnbaVPzd0EyaQ?pwd=zkh4
提取码:zkh4
三、程序设计
1. 创建主场景
mainscene
MainScene::MainScene(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainScene)
{ui->setupUi(this);//配置主场景//设置窗口固定大小setFixedSize(320,588);//设置窗口图标setWindowIcon(QIcon(":/res/Coin0001.png"));//设置窗口标题setWindowTitle("翻金币主场景");//退出按钮实现connect(ui->actionquit,&QAction::triggered,[=](){this->close();});//准备开始按钮的音效QSound *startSound=new QSound(":/res/TapButtonSound.wav");//startSound->setLoops(10); //代表循环次数,如果是-1代表无线循环startSound->play();//开始按钮MyPushButton *startBtn=new MyPushButton(":/res/MenuSceneStartButton.png");startBtn->setParent(this);startBtn->move(this->width()*0.35,this->height()*0.7); //移动到合适的位置//实例化选择关卡场景chooseSence=new ChooseLevelScene;//监听选择关卡的返回按钮信号connect(chooseSence,&ChooseLevelScene::chooseSceneBack,this,[=](){this->setGeometry(chooseSence->geometry());chooseSence->hide(); //将选择关卡隐藏掉this->show(); //重新显示主场景});//点击start按钮 实现弹跳效果connect(startBtn,&MyPushButton::clicked,[=](){//播放开始音效资源startSound->play();//弹跳效果startBtn->zoom1();startBtn->zoom2();//延时进入到选择关卡场景中QTimer::singleShot(500,this,[=](){ //延时500ms在进行以下操作//设置chooseScene场景的位置chooseSence->setGeometry(this->geometry());//自身隐藏this->hide();//显示选择关卡场景chooseSence->show();});});}void MainScene::paintEvent(QPaintEvent *)
{QPainter painter(this); //声明画家//1、画背景图QPixmap pix; //声明对象pix.load(":/res/PlayLevelSceneBg.png"); //在对象中加载图片painter.drawPixmap(0,0,this->width(),this->height(),pix); //画背景图//2、画背景上图标pix.load(":/res/Title.png"); //加载图片pix=pix.scaled(pix.width()*0.5,pix.height()*0.5); //因图标有点大,所以在这里按比例缩小一倍painter.drawPixmap(10,30,pix); //画上图标
}MainScene::~MainScene()
{delete ui;
}
2. 自定义开始按钮
mypushbutton
MyPushButton::MyPushButton (QString normalImg,QString pressImg)
{this->normalImgPath=normalImg;this->pressImgPath=pressImg;QPixmap pix;bool ret=pix.load(normalImg);if(!ret){qDebug()<<"图片加载失败";return;}//设置图片固定大小this->setFixedSize(pix.width(),pix.height());//设置不规则图片样式this->setStyleSheet("QPushButton{border:0px;}");//设置图标this->setIcon(pix);//设置图标大小this->setIconSize(QSize(pix.width(),pix.height()));}void MyPushButton::zoom1()
{//创建动态对象QPropertyAnimation *animation=new QPropertyAnimation(this,"geometry");//设置动画时间间隔animation->setDuration(200); //200ms//起始位置animation->setStartValue(QRect(this->x(),this->y(),this->width(),this->height()));//结束位置animation->setEndValue(QRect(this->x(),this->y()+10,this->width(),this->height()));//设置弹跳曲线animation->setEasingCurve(QEasingCurve::OutBounce);//执行动画animation->start();
}void MyPushButton::zoom2()
{//创建动态对象QPropertyAnimation *animation=new QPropertyAnimation(this,"geometry");//设置动画时间间隔animation->setDuration(200); //200ms//起始位置animation->setStartValue(QRect(this->x(),this->y()+10,this->width(),this->height()));//结束位置animation->setEndValue(QRect(this->x(),this->y(),this->width(),this->height()));//设置弹跳曲线animation->setEasingCurve(QEasingCurve::OutBounce);//执行动画animation->start();
}void MyPushButton:: mousePressEvent(QMouseEvent *e)
{if(this->pressImgPath!=" ") //传入的按下图片不为空 说明需要有按下状态 切换图片{QPixmap pix;bool ret=pix.load(pressImgPath);if(!ret){qDebug()<<"图片加载失败";return;}//设置图片固定大小this->setFixedSize(pix.width(),pix.height());//设置不规则图片样式this->setStyleSheet("QPushButton{border:0px;}");//设置图标this->setIcon(pix);//设置图标大小this->setIconSize(QSize(pix.width(),pix.height()));}return QPushButton:: mousePressEvent(e);
}void MyPushButton:: mouseReleaseEvent(QMouseEvent *e)
{if(this->pressImgPath!=" ") //传入的按下图片不为空 说明需要有按下状态 切换成初始图片{QPixmap pix;bool ret=pix.load(normalImgPath);if(!ret){qDebug()<<"图片加载失败";return;}//设置图片固定大小this->setFixedSize(pix.width(),pix.height());//设置不规则图片样式this->setStyleSheet("QPushButton{border:0px;}");//设置图标this->setIcon(pix);//设置图标大小this->setIconSize(QSize(pix.width(),pix.height()));}return QPushButton:: mouseReleaseEvent(e);
}
3. 创建选择关卡场景
chooselevelscene
ChooseLevelScene::ChooseLevelScene(QWidget *parent) : QMainWindow(parent)
{//配置选择关卡场景this->setFixedSize(320,588);//设置图标this->setWindowIcon(QPixmap(":/res/Coin0001.png"));//设置标题this->setWindowTitle("选择关卡场景");//创建菜单栏QMenuBar *bar=menuBar();setMenuBar(bar);//创建开始菜单QMenu *startMenu=bar->addMenu("开始");//创建退出 菜单项QAction *quitAction=startMenu->addAction("退出");//点击退出 实现退出游戏connect(quitAction,&QAction::triggered,[=](){this->close();});//选择关卡按钮音效QSound *chooseSound=new QSound(":/res/TapButtonSound.wav");//返回按钮音效QSound *backSound=new QSound(":/res/BackButtonSound.wav");//返回按钮MyPushButton *backBtn=new MyPushButton(":/res/BackButton.png",":/res/BackButtonSelected.png");backBtn->setParent(this);backBtn->move(this->width()-backBtn->width(),this->height()-backBtn->height());//点击返回connect(backBtn,&MyPushButton::clicked,[=](){//播放返回按钮音效backSound->play();//qDebug()<<"点击了返回按钮";//告诉主场景 我返回了,主场景监听ChooseSceneBack的返回按钮//延时返回QTimer::singleShot(500,this,[=](){emit this->chooseSceneBack();});});//创建选择关卡的按钮for(int i=0;i<20;i++){MyPushButton *menuBtn=new MyPushButton(":/res/LevelIcon.png");menuBtn->setParent(this);menuBtn->move(25+i%4*70,130+i/4*70);//监听每个按钮的点击事件connect(menuBtn,&MyPushButton::clicked,[=](){//播放选择关卡音效chooseSound->play();QString str=QString("你选择的是第 %1 关").arg(i+1);qDebug()<<str;//进入到游戏场景this->hide(); //将选关场景隐藏掉play=new PlayScene(i+1); //创建游戏场景//设置游戏场景的初始位置play->setGeometry(this->geometry());play->show(); //显示游戏场景connect(play,&PlayScene::chooseSceneBack,[=](){this->setGeometry(play->geometry());this->show();delete play;play=NULL;});});QLabel *label=new QLabel;label->setParent(this);label->setFixedSize(menuBtn->width(),menuBtn->height());label->setText(QString::number(i+1));label->move(25+i%4*70,130+i/4*70);//设置label上的文字对齐方式 水平居中和垂直居中label->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);//设置让鼠标进行穿透 51号属性label->setAttribute(Qt::WA_TransparentForMouseEvents);}
}void ChooseLevelScene::paintEvent(QPaintEvent *)
{//加载背景QPainter painter(this);QPixmap pix;pix.load(":/res/OtherSceneBg.png");painter.drawPixmap(0,0,this->width(),this->height(),pix);//加载需要插入的背景标题图pix.load(":/res/Title.png");painter.drawPixmap((this->width()-pix.width())*0.5,30,pix.width(),pix.height(),pix);
}
4. 创建翻金币场景
playscene
PlayScene::PlayScene(int levelNum)
{QString str=QString("进入了第 %1 关").arg(levelNum);qDebug()<<str;this->levelIndex=levelNum;//初始化游戏场景//设置固定大小this->setFixedSize(320,588);//设置图标this->setWindowIcon(QPixmap(":/res/Coin0001.png"));//设置标题this->setWindowTitle("翻金币场景");//创建菜单栏QMenuBar *bar=menuBar();setMenuBar(bar);//创建开始菜单QMenu *startMenu=bar->addMenu("开始");//创建退出 菜单项QAction *quitAction=startMenu->addAction("退出");//点击退出 实现退出游戏connect(quitAction,&QAction::triggered,[=](){this->close();});//添加音效资源//返回按钮音效QSound *backSound=new QSound(":/res/BackButtonSelected.png",this);//翻金币音效QSound *flipSound=new QSound(":/res/ConFlipSound.wav",this);//胜利按钮音效QSound *winSound=new QSound(":/res/LevelWinSound.wav",this);//返回按钮MyPushButton *backBtn=new MyPushButton(":/res/BackButton.png",":/res/BackButtonSelected.png");backBtn->setParent(this);backBtn->move(this->width()-backBtn->width(),this->height()-backBtn->height());//点击返回connect(backBtn,&MyPushButton::clicked,[=](){//播放返回按钮音效backSound->play();qDebug()<<"翻金币场景中:点击了返回按钮";QTimer::singleShot(500,this,[=](){emit this->chooseSceneBack();});});//显示当前关卡数QLabel *label=new QLabel; //创建QLabel类控件对象label->setParent(this);QFont font; //创建字体对象font.setFamily("华文新魏"); //设置字体font.setPointSize(20); //设置字号大小QString str1=QString("Level: %1").arg(this->levelIndex);label->setFont(font); //将字体设置到标签控件中label->setText(str1); //设置控件文本( Level: %1 )label->setGeometry(30,this->height()-50,120,50); //设置控件的大小和位置dataConfig config;//初始化每个关卡的二维数组for(int i=0;i<4;i++){for(int j=0;j<4;j++){this->gameArray[i][j]=config.mData[this->levelIndex][i][j];}}//胜利图片显示QLabel *winLabel=new QLabel;QPixmap temPix;temPix.load(":/res/LevelCompletedDialogBg.png");winLabel->setGeometry(0,0,temPix.width(),temPix.height());winLabel->setPixmap(temPix);winLabel->setParent(this);winLabel->move((this->width()-temPix.width()*0.5),-temPix.height());//显示金币的背景图案for(int i=0;i<4;i++){for(int j=0;j<4;j++){//绘制背景图片QPixmap pix=QPixmap(":/res/BoardNode(1).png");QLabel *label1=new QLabel;label1->setGeometry(0,0,pix.width(),pix.height());label1->setPixmap(pix);label1->setParent(this);label1->move(57+i*50,200+j*50);//创建金币QString str;if(this->gameArray[i][j]==1){//显示金币str=":/res/Coin0001.png";}else{str=":/res/Coin0008.png";}MyCoin *coin=new MyCoin(str);coin->setParent(this);coin->move(59+i*50,204+j*50);//给金币赋值coin->posX=i;coin->posY=j;coin->flag=this->gameArray[i][j]; //1正面 0反面//将金币放入到 金币的二维数组里 以便于后期的维护coinBtn[i][j]=coin;//点击金币 进行翻转connect(coin,&MyCoin::clicked,[=](){//翻金币音效flipSound->play();for(int i=0;i<4;i++){for(int j=0;j<4;j++){this->coinBtn[i][j]->isWin=true;}}coin->changeFlag();this->gameArray[i][j]=this->gameArray[i][j]==0?1:0;//翻转周围硬币,延时翻转QTimer::singleShot(300,this,[=](){//周围的右侧金币反转的条件if(coin->posX+1<=3){coinBtn[coin->posX+1][coin->posY]->changeFlag();this->gameArray[coin->posX+1][coin->posY]=this->gameArray[coin->posX+1][coin->posY]==0?1:0;}//周围的左侧金币反转的条件if(coin->posX-1>=0){coinBtn[coin->posX-1][coin->posY]->changeFlag();this->gameArray[coin->posX-1][coin->posY]=this->gameArray[coin->posX-1][coin->posY]==0?1:0;}//周围上侧的金币反转的条件if(coin->posY+1<=3){coinBtn[coin->posX][coin->posY+1]->changeFlag();this->gameArray[coin->posX][coin->posY+1]=this->gameArray[coin->posX][coin->posY+1]==0?1:0;}//周围上侧的金币反转的条件if(coin->posY-1>=0){coinBtn[coin->posX][coin->posY-1]->changeFlag();this->gameArray[coin->posX][coin->posY-1]=this->gameArray[coin->posX][coin->posY-1]==0?1:0;}for(int i=0;i<4;i++){for(int j=0;j<4;j++){this->coinBtn[i][j]->isWin=false;}}//判断是否胜利this->isWin=true;for(int i=0;i<4;i++){for(int j=0;j<4;j++){if(coinBtn[i][j]->flag==false) //只要有一个是反面,那就算失败{this->isWin=false;break;}}}if(this->isWin==true){//添加胜利音效winSound->play();qDebug()<<"游戏胜利";//将所有按钮的胜利标志改为true 如果再次点击按钮,直接return,不作响应for(int i=0;i<4;i++){for(int j=0;j<4;j++){coinBtn[i][j]->isWin=true;}}//将胜利的图片移动下来QPropertyAnimation *animation=new QPropertyAnimation(winLabel,"geometry");//设置时间间隔animation->setDuration(1000);//设置开始位置animation->setStartValue(QRect(winLabel->x()-150,winLabel->y(),winLabel->width(),winLabel->height()));//设置结束位置animation->setEndValue(QRect(winLabel->x()-150,winLabel->y()+120,winLabel->width(),winLabel->height()));//设置缓和曲线animation->setEasingCurve(QEasingCurve::OutBounce);//执行动画animation->start();}});});}}
}void PlayScene::paintEvent(QPaintEvent *)
{//创建背景QPainter painter(this);QPixmap pix;pix.load(":/res/PlayLevelSceneBg.png");painter.drawPixmap(0,0,this->width(),this->height(),pix);//加载标题pix.load(":/res/Title.png");pix=pix.scaled(pix.width()*0.5,pix.height()*0.5);painter.drawPixmap(10,30,pix.width(),pix.height(),pix);
}
5. 设置金币及其翻转效果
mycoin
MyCoin::MyCoin(QString btnImg){QPixmap pix;bool ret=pix.load(btnImg);if(!ret){QString str=QString("图片 %1 加载失败").arg(btnImg);qDebug()<<str;return;}this->setFixedSize(pix.width(),pix.height());this->setStyleSheet("QPushButton{border:0px;}");this->setIcon(pix);this->setIconSize(QSize(pix.width(),pix.height()));//初始化定时器对象timer1=new QTimer(this);timer2=new QTimer(this);//监听正面翻反面的信号,并且翻转金币connect(timer1,&QTimer::timeout,[=](){QPixmap pix;QString str=QString(":/res/Coin000%1.png").arg(this->min++);pix.load(str);this->setFixedSize(pix.width(),pix.height());this->setStyleSheet("QPushButton{border:0px;}");this->setIcon(pix);this->setIconSize(QSize(pix.width(),pix.height()));//判断 如果翻完了,将min重置为1if(this->min > this->max){this->min=1;isAnimation=false; //关闭做动画timer1->stop();}});//监听反面翻正面的信号,并且翻转金币connect(timer2,&QTimer::timeout,[=](){QPixmap pix;QString str=QString(":/res/Coin000%1.png").arg(this->max--);pix.load(str);this->setFixedSize(pix.width(),pix.height());this->setStyleSheet("QPushButton{border:0px;}");this->setIcon(pix);this->setIconSize(QSize(pix.width(),pix.height()));//判断 如果翻完了,将max重置为8if(this->max < this->min){this->max=8;isAnimation=false; //关闭做动画timer2->stop();}});}//改变正反面标志的方法void MyCoin::changeFlag(){//如果是正面 翻成反面if(this->flag){//开始正面翻反面的定时器timer1->start(30);isAnimation=true; //开始做动画this->flag=false;}else //反面翻正面{timer2->start(30);isAnimation=true; //开始做动画this->flag=true;}}void MyCoin::mousePressEvent(QMouseEvent *e){if(this->isAnimation|this->isWin){return;}else{QPushButton::mousePressEvent(e);}}
6. 设置关卡的难易程度
dataconfig
dataConfig::dataConfig(QObject *parent) : QObject(parent)
{int array1[4][4] = {{1, 1, 1, 1},{1, 1, 0, 1},{1, 0, 0, 0},{1, 1, 0, 1} } ;QVector< QVector<int>> v;for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array1[i][j]);}v.push_back(v1);}mData.insert(1,v);int array2[4][4] = { {1, 0, 1, 1},{0, 0, 1, 1},{1, 1, 0, 0},{1, 1, 0, 1}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array2[i][j]);}v.push_back(v1);}mData.insert(2,v);int array3[4][4] = { {0, 0, 0, 0},{0, 1, 1, 0},{0, 1, 1, 0},{0, 0, 0, 0}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array3[i][j]);}v.push_back(v1);}mData.insert(3,v);int array4[4][4] = { {0, 1, 1, 1},{1, 0, 0, 1},{1, 0, 1, 1},{1, 1, 1, 1}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array4[i][j]);}v.push_back(v1);}mData.insert(4,v);int array5[4][4] = { {1, 0, 0, 1},{0, 0, 0, 0},{0, 0, 0, 0},{1, 0, 0, 1}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array5[i][j]);}v.push_back(v1);}mData.insert(5,v);int array6[4][4] = { {1, 0, 0, 1},{0, 1, 1, 0},{0, 1, 1, 0},{1, 0, 0, 1}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array6[i][j]);}v.push_back(v1);}mData.insert(6,v);int array7[4][4] = { {0, 1, 1, 1},{1, 0, 1, 1},{1, 1, 0, 1},{1, 1, 1, 0}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array7[i][j]);}v.push_back(v1);}mData.insert(7,v);int array8[4][4] = { {0, 1, 0, 1},{1, 0, 0, 0},{0, 0, 0, 1},{1, 0, 1, 0}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array8[i][j]);}v.push_back(v1);}mData.insert(8,v);int array9[4][4] = { {1, 0, 1, 0},{1, 0, 1, 0},{0, 0, 1, 0},{1, 0, 0, 1}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array9[i][j]);}v.push_back(v1);}mData.insert(9,v);int array10[4][4] = { {1, 0, 1, 1},{1, 1, 0, 0},{0, 0, 1, 1},{1, 1, 0, 1}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array10[i][j]);}v.push_back(v1);}mData.insert(10,v);int array11[4][4] = { {0, 1, 1, 0},{1, 0, 0, 1},{1, 0, 0, 1},{0, 1, 1, 0}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array11[i][j]);}v.push_back(v1);}mData.insert(11,v);int array12[4][4] = { {0, 1, 1, 0},{0, 0, 0, 0},{1, 1, 1, 1},{0, 0, 0, 0}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array12[i][j]);}v.push_back(v1);}mData.insert(12,v);int array13[4][4] = { {0, 1, 1, 0},{0, 0, 0, 0},{0, 0, 0, 0},{0, 1, 1, 0}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array13[i][j]);}v.push_back(v1);}mData.insert(13,v);int array14[4][4] = { {1, 0, 1, 1},{0, 1, 0, 1},{1, 0, 1, 0},{1, 1, 0, 1}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array14[i][j]);}v.push_back(v1);}mData.insert(14,v);int array15[4][4] = { {0, 1, 0, 1},{1, 0, 0, 0},{1, 0, 0, 0},{0, 1, 0, 1}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array15[i][j]);}v.push_back(v1);}mData.insert(15,v);int array16[4][4] = { {0, 1, 1, 0},{1, 1, 1, 1},{1, 1, 1, 1},{0, 1, 1, 0}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array16[i][j]);}v.push_back(v1);}mData.insert(16,v);int array17[4][4] = { {0, 1, 1, 1},{0, 1, 0, 0},{0, 0, 1, 0},{1, 1, 1, 0}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array17[i][j]);}v.push_back(v1);}mData.insert(17,v);int array18[4][4] = { {0, 0, 0, 1},{0, 0, 1, 0},{0, 1, 0, 0},{1, 0, 0, 0}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array18[i][j]);}v.push_back(v1);}mData.insert(18,v);int array19[4][4] = { {0, 1, 0, 0},{0, 1, 1, 0},{0, 0, 1, 1},{0, 0, 0, 0}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array19[i][j]);}v.push_back(v1);}mData.insert(19,v);int array20[4][4] = { {0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}} ;v.clear();for(int i = 0 ; i < 4;i++){QVector<int>v1;for(int j = 0 ; j < 4;j++){v1.push_back(array20[i][j]);}v.push_back(v1);}mData.insert(20,v);