Qt5实现飞机大战1.0(下)

承接上篇,咱来继续说:

四、爆炸动画的实现
当战机和敌机发生碰撞的时候,本程序设定会显示一个爆炸的动画。对于爆炸的显示,原本的想法是利用QMovie显示爆炸的gif动态图,但是这样的话会阻碍绘图事件和定时器事件,我尝试了一下,程序每次都会崩(当然,如果重新建立一个线程。可能会行)。后来转变了思路,爆炸动画的显示和飞机移动动画的显示基本上不是一个东西吗?不是可以利用重绘事件和定时器事件 来显示动画吗?照着这个思路。主要代码如下:

//重绘事件中绘制爆炸
        foreach(Explosion * temp_exp,exp_list)
        {
            if(temp_exp->GetCurPicNum()<=EXPLOSION_IMG_NUM)
                painter.drawPixmap(temp_exp->GetPos(),*(temp_exp->exp_img_list[temp_exp->GetCurPicNum()-1]));
        }
        
if(IsAttacked == true )       //子弹攻击到敌机
                {
                    EneFishIsAttacked();

                    Explosion *temp_exp = new Explosion;        //产生爆炸
                    temp_exp->SetPos(temp_fish->pos);
                    exp_list.append(temp_exp);

                    myPlane->my_bulles.removeOne(*iter_bul);      //移除子弹
                    delete temp_bul;

                    fish_list.removeOne(*iter);        //小虾米碰撞到子弹,删除敌机
                    delete temp_fish;

                    break;
                }

//判断我方战机是否碰撞到敌方战机
                QRect myPlane_rect(myPlane->pos,QSize(myPlane->img.width(),myPlane->img.height()));
                IsCon = temp.intersects(myPlane_rect);

                if(IsCon == true)
                {
                    Explosion *temp_exp = new Explosion;        //产生爆炸
                    temp_exp->SetPos(temp_fish->pos);
                    exp_list.append(temp_exp);
                    fish_list.removeOne(*iter);        //小虾米碰撞到我方飞机,删除敌机
                    delete temp_fish;
                    EneFishIsAttacked();
                    MyPlaneIsAttacked();        //我方战机损失生命力
                    break;
                }
//切换爆炸图片,显示爆炸
void Widget::ShowExplosion()
{
    QLinkedList::iterator iter;
    for(iter = exp_list.begin();iter !=exp_list.end();++iter)       //遍历爆炸列表,更换下一张爆炸图片
    {
        Explosion *temp_exp = *iter;

        if(temp_exp->NextPic() == false)    //爆炸显示结束,删除爆炸
        {
            exp_list.removeOne(*iter);
            delete temp_exp;
        }
    }

}

上述代码的主要含义就是利用定时器事件,在检测战机和敌机、敌机和子弹发生碰撞了之后,就会产生一个爆炸,然后在重绘事件中绘制这个爆炸。当然,还得再定时器事件中切换爆炸的图片。产生的效果如下:
Qt5实现飞机大战1.0(下)_第1张图片
分离的爆炸图片是8个bmp图像,csdn上不能上传,我把它放在我的资源里了,有需要的可以下载使用。

五、飞机图片透明效果的实现
在图像的绘制中,飞机是一张背景为黑色的图片。如下图所示,
战机图片

需要把飞机的边缘遮掩住。这里使用了QPixmap自带的一个遮掩函数QPixmap::setmask(mask)函数。代码如下:

  //使飞机边框透明
    img.load(":/img/myplane.bmp");
    QBitmap mask =  img.createMaskFromColor(QColor(0,0,0),Qt::MaskInColor);
    img.setMask(mask);

照我的理解:这个函数可以根据你的mask把显示的图片中相应的部分变成透明的。在这里我设置黑色为透明的。产生的效果如下:
Qt5实现飞机大战1.0(下)_第2张图片

同理,敌机图片的边缘和爆炸图片的边缘都是这样产生透明效果的。

六、背景图的移动
为了使飞机产生不断前进的效果,需要把背景不断移动。根据上面的思路,对,这里也是产生相同的做法。利用定时器和重绘事件,不断重绘背景图片。具体来说,采用 两张图片,一张图片不断往下移动,另一张不断从上补充。(这里的两张背景图片采用的是相同的图片,所以中间衔接的地方有些不流畅)。主要代码如下:

 //绘制动态背景
        painter.drawPixmap(0,back_spe,back);
        painter.drawPixmap(0,back_spe-back.height(),back);

这里painter.draw()函数可以指定绘制图像的区域。

Qt5实现飞机大战1.0(下)_第3张图片Qt5实现飞机大战1.0(下)_第4张图片
七、游戏状态的转换
本程序采用了三个状态,开始欢迎状态,运行状态和结束状态。这三种状态都是在一个QWidget中切换的。开始状态时,点击回车键,进入运行状态;运行状态,玩家over时,进入结束状态;结束状态,点击回车键,进入运行状态。代码嵌入在其他的步骤中了,在此就不贴了。三种状态的图片如下:

这里采用的方法也有点low,就是用if语句判断当前的状态,然后进行响应的操作。这在重绘事件和按键事件中都需要进行判断。(比较高级点的方法应该是利用状态机来实现,现在弄得还不是很清楚,暂且就不用了吧)

八、不足与展望
稍微正式点,最后说点不足和展望。作为一个简易版的飞机大战,本程序不足之处有以下
1、未添加音效,如爆炸音效。
2、未添加闯关模式、大招模式
3、未添加敌机的Boss
4、未采用好的框架。(如图形视图框架、动画框架和状态机框架)
。。。。

这是1.0版,等什么时候学的再深点,在编出2.0版的。

最后的整个工程的源码见:点这儿

你可能感兴趣的:(我的小项目)