4、创建翻金币场景
4.1创建翻金币界面
设计好主场景以及选择关卡界面以后,就来到了最重要的一环:翻金币。首先还是创建一个cpp文件命名为PlayScene。第一步在选择关卡中声明PlayScene *pScene = NULL;
方便后面使用。点击选择某一关卡按钮以后会跳入该场景,此时该场景需要显示出来,来选择关卡界面需要隐藏。第二步就是注视掉原来PlayScene.h中的构造函数,自己重回写一个构造函数,并写一个成员变量用于记录所选择的关卡数,具体的代码与结果如下:
//进入到了游戏场景
this->hide();//选择关卡界面隐藏
play = new PlayScene(i+1);//这是将选择哪一个关卡告诉play
play->show();//某一关卡显示
PlayScene::PlayScene(int levelNum)
{
QString str = QString("进入了第 %1 关").arg(levelNum);
qDebug()<<str;
this->levelIndex = levelNum;
}
4.2翻转金币的基本配置
结果出来以后,发现所有关卡的界面很丑,什么都没有,接着就是对它的一顿操作了,主要有:背景,图标、大小、标题以及返回按钮(返回到选择关卡页面)还有就是菜单栏。总之代码与前面的一样,这里不在赘述。直接看结果,如下:
4.3增加关卡标签
以上设置好以后,就要设置关卡标签。在playscene代码以及结果如下:
QLabel *Label = new QLabel;
Label->setParent(this);
QFont font;
font.setFamily("华文新魏");//关卡标签的字体
font.setPointSize(20);//大小
Label->setFont(font);
QString str1 = QString("Level %1").arg(this->levelIndex);//关卡
Label->setText(str1);
Label->setGeometry(QRect(30,this->height()-50,120,50));//位置
4.4增加金币背景图片
创建金币的背景图片,在此放置金币。逻辑比较简单,用2个for循环实现,代码与结果为:
for(int i = 0 ; i < 4;i++)
{
for(int j = 0 ; j < 4; j++)
{
//绘制背景图片
QLabel* label = new QLabel;
label->setGeometry(0,0,50,50);
label->setPixmap(QPixmap(":/res/BoardNode.png"));
label->setParent(this);
label->move(57 + i*50,200+j*50);
}
}
4.5封装金币类
4.5.1在背景上图片中增加金币
金币作为本游戏最重要的一部分,拥有点击、翻转的特效。因此将金币类封装在一个类中,称之为“MyCoin",专门用于金币功能的实现。首先实现金币翻转功能,其实金币翻转就是8张图片快速切换而实现的,在给翻转金币的时候给用户呈现的无非就是金币或者银币。因此注释掉原来的构造函数,自己重新写一个构造函数,参数是金币或者银币的路径MyCoin(QString coinpath);
在MyCoin.cpp中实现,需要说明的是,由于金币翻转需要按下因此需要更改其父类为QPushButton,代码及结果为:
4.6引入关卡数据
接着就是创建每一个关卡的数据,需要引入关卡数据文件,文件中记录了关卡的二维数组的数据。右键点击.pro选择添加现有文件,选择dataConfig.h
与dataConfig.cpp
文件就好。在公有接口可以看到QMap<int, QVector< QVector<int> > >mData;
其中int代表关卡数,而QVector<QVector>则记录着关卡中的二维数组。需要说明的是QMap<key,T>容器,它提供了一个字典(或者说关联的数组),一个键映射到一个值。在公有接口处是的int就是对应的key,而QVector<QVector>就是对应的T,这样就比较好理解。
在playscene.h中声明一个成员变量int gameArray[4][4];
,用于记录当前关卡的二维数据。然后在playscene.cpp初始化二维数组,接着根据数组中的数值(0或1)判断是金币还是银币。代码如下:
//初始化每一个关卡的二维数组
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];
//后面就可以根据gameArray[i][j]中的数据决定是金币或者是银币了
}
}
分割///
//创建金币 做一个判断:金币或者是银币
QString str;
if(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);//金币放置的位置与金币背景的位置一样
4.7翻转金币
金币放上去以后就要实现金币的翻转,也就是按一下就反转成银币。首先在mycoin.h中定义币的属性包括x、y位置以及是否翻转了。然后声明翻转的函数void changFlag();
,在此函数下创建2个定时器用于记录正面翻到反面与反面翻到正面,以及定义2个用于记录照片个数的成员变量(因为是8张照片的翻转效果)。
void changFlag();
QTimer timer1;//正面->反面的定时器
QTimer timer2;//反面->正面的定时器
int min=1;
int max=8;
.cpp中实现为:
oid MyCoin::changFlag()//改变金币银币面的标志
{
if(this->flag) //如果是金币面,执行下列代码
{
timer1->start(30);
this->flag = false;
}
else //银币面执行下列代码
{
timer2->start(30);
this->flag = true;
}
}
然后在构造函数中做监听操作,做出反应并结束定时器。接着在playscene.cpp中监听金币按下操作,并改变币种状态。
//监听的是金币面翻银币面的信号
connect(timer1,&QTimer::timeout,[=](){
QPixmap pix;
QString str = QString(":/res/Coin000%1").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重置为1
if(this->min>this->max)
{
this->min=1;
timer1->stop();
}
});
//监听的是银币面翻金币面的信号
connect(timer2,&QTimer::timeout,[=](){
QPixmap pix;
QString str = QString(":/res/Coin000%1").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()));
//如果翻转结束了,将min重置为1
if(this->max<this->min)
{
this->max=8;
timer2->stop();
}
});
//点击金币进行翻转
connect(coin,&MyCoin::clicked,[=](){
coin->changFlag();
this->gameArray[i][j] = this->gameArray[i][j]==0?1:0;//改变币种的状态
});
4.8翻转周围金币
以上分析就基本实现了金币翻银币,银币翻金币的操作。现在的问题就是按一下就只能翻转一个,而我们最终要实现的是按某一个金币周围的金币进行翻转。其实就是位置的改变罢了,比如要翻转左侧的金币就if(coin->posX+1<=3)
,其余的类似。代码与结果如下:
//实现周围金币的翻转
if(coin->posX+1<=3)//右侧翻转条件
{
coinBtn[coin->posX+1][coin->poxY]->changFlag();
this->gameArray[coin->posX+1][coin->poxY] = this->gameArray[coin->posX+1][coin->poxY]==0?1:0;
}
if(coin->posX-1>0)//左侧翻转条件
{
coinBtn[coin->posX-1][coin->poxY]->changFlag();
this->gameArray[coin->posX-1][coin->poxY] = this->gameArray[coin->posX-1][coin->poxY]==0?1:0;
}
if(coin->poxY+1<=3)//上侧翻转条件
{
coinBtn[coin->posX][coin->poxY+1]->changFlag();
this->gameArray[coin->posX][coin->poxY+1] = this->gameArray[coin->posX][coin->poxY+1]==0?1:0;
}
if(coin->poxY-1>0)//下侧翻转条件
{
coinBtn[coin->posX][coin->poxY-1]->changFlag();
this->gameArray[coin->posX][coin->poxY-1] = this->gameArray[coin->posX][coin->poxY-1]==0?1:0;
}
4.9判断胜利并显示胜利图像
项目马上就结束了,接下来就是要判断胜利,并且显示胜利的标志。在playscene.h中加入判断是否胜利的标志,一开始就给true。当周围的金币否翻转结束后,判断是否成功。成功标志是:金币都翻转为银币。当胜利以后禁止任何一个金币翻转,具体的代码如下:
//判断是否胜利了
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)
{
qDebug()<<"胜利了";
if(this->isWin==true)
{
qDebug()<<"胜利了";
//将所有按钮的胜利标志设为true
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
coinBtn[i][j]->isWin=true;
}
}
}
}
//显示胜利的标志
QLabel* winLabel = new QLabel;
QPixmap tmpPix;
tmpPix.load(":/res/LevelCompletedDialogBg.png");
winLabel->setGeometry(0,0,tmpPix.width(),tmpPix.height());
winLabel->setPixmap(tmpPix);
winLabel->setParent(this);
winLabel->move( (this->width() - tmpPix.width())*0.5 , -tmpPix.height());
胜利的特效///
```cpp
if(this->isWin)
{
qDebug() << "胜利";
QPropertyAnimation * animation1 = new QPropertyAnimation(winLabel,"geometry");
animation1->setDuration(1000);
animation1->setStartValue(QRect(winLabel->x(),winLabel->y(),winLabel->width(),winLabel->height()));
animation1->setEndValue(QRect(winLabel->x(),winLabel->y()+170,winLabel->width(),winLabel->height()));
animation1->setEasingCurve(QEasingCurve::OutBounce);
animation1->start();
}