8玩家发射子弹
玩家发射子弹制作步骤如下:
英雄飞机添加新的成员属性实现发射成员函数主场景控制子弹发射8.1飞机添加新成员属性
在config.h中添加新的配置数据
#defineBULLET_NUM30//弹匣中子弹总数#defineBULLET_INTERVAL20//发射子弹时间间隔
在HeroPlane.h中新增成员属性如下:
//弹匣Bulletm_bullets[BULLET_NUM];//发射间隔记录intm_recorder;
8.2成员函数补充
在构造函数HeroPlane中初始化发生间隔记录
//初始化发射间隔记录m_recorder=0;
之前在英雄飞机类中预留的一个shoot函数我们进行实现,代码如下:
voidHeroPlane::shoot(){//累加时间间隔记录变量m_recorder++;//判断如果记录数字未达到发射间隔,直接returnif(m_recorderBULLET_INTERVAL){return;}//到达发射时间处理//重置发射时间间隔记录m_recorder=0;//发射子弹for(inti=0;iBULLET_NUM;i++){//如果是空闲的子弹进行发射if(m_bullets[i].m_Free){//将改子弹空闲状态改为假m_bullets[i].m_Free=false;//设置发射的子弹坐标m_bullets[i].m_X=m_X+m_Rect.width()*0.5-10;m_bullets[i].m_Y=m_Y-25;break;}}}
8.3主场景中实现发射子弹
在MainScene.cpp的updatePosition成员函数中追加如下代码
//发射子弹m_hero.shoot();//计算子弹坐标for(inti=0;iBULLET_NUM;i++){//如果子弹状态为非空闲,计算发射位置if(!m_hero.m_bullets[i].m_Free){m_hero.m_bullets[i].updatePosition();}}
在MainScene.cpp的paintEvent成员函数中追加如下代码:
//绘制子弹for(inti=0;iBULLET_NUM;i++){//如果子弹状态为非空闲,计算发射位置if(!m_hero.m_bullets[i].m_Free){painter.drawPixmap(m_hero.m_bullets[i].m_X,m_hero.m_bullets[i].m_Y,m_hero.m_bullets[i].m_Bullet);}}
测试运行,玩家可以发射子弹
9敌机制作
敌机制作与子弹制作原理类似,也是每隔一定的时间让敌机出场
制作步骤如下:
创建敌机文件和类添加敌机类中的成员函数和成员属性实现成员函数敌机出场测试敌机9.1创建敌机文件和类
创建EnemyPlane类以及生成对应的文件
创建好后生成enemyPlane.h和enemyPlane.cpp两个文件
9.2敌机成员函数和成员属性
在enemyPlane.h中添加如下代码:
#ifndefENEMYPLANE_H#defineENEMYPLANE_H#includeQPixmapclassEnemyPlane{public:EnemyPlane();//更新坐标voidupdatePosition();public://敌机资源对象QPixmapm_enemy;//位置intm_X;intm_Y;//敌机的矩形边框(碰撞检测)QRectm_Rect;//状态boolm_Free;//速度intm_Speed;};#endif//ENEMYPLANE_H
9.3敌机成员函数实现
在config.h中追加敌机配置信息
/**********敌机配置数据**********/#defineENEMY_PATH:/res/img-plane_5.png//敌机资源图片#defineENEMY_SPEED5//敌机移动速度#defineENEMY_NUM20//敌机总数量#defineENEMY_INTERVAL30//敌机出场时间间隔
在enemyPlane.cpp中实现成员函数,代码如下:
EnemyPlane::EnemyPlane(){//敌机资源加载m_enemy.load(ENEMY_PATH);//敌机位置m_X=0;m_Y=0;//敌机状态m_Free=true;//敌机速度m_Speed=ENEMY_SPEED;//敌机矩形m_Rect.setWidth(m_enemy.width());m_Rect.setHeight(m_enemy.height());m_Rect.moveTo(m_X,m_Y);}voidEnemyPlane::updatePosition(){//空闲状态,不计算坐标if(m_Free){return;}m_Y+=m_Speed;m_Rect.moveTo(m_X,m_Y);if(m_Y=GAME_HEIGHT+m_Rect.height()){m_Free=true;}}
9.4敌机出场
在MainScene.h中追加敌机出场的成员函数
在MainScene.h中追加敌机数组和敌机出场间隔记录的成员属性
//敌机出场voidenemyToScene();//敌机数组EnemyPlanem_enemys[ENEMY_NUM];//敌机出场间隔记录intm_recorder;
初始化间隔记录属性,在MainScene.cpp的initScene成员函数中追加
m_recorder=0;
实现成员函数enemyToScene
voidMainScene::enemyToScene(){m_recorder++;if(m_recorderENEMY_INTERVAL){return;}m_recorder=0;for(inti=0;iENEMY_NUM;i++){if(m_enemys[i].m_Free){//敌机空闲状态改为falsem_enemys[i].m_Free=false;//设置坐标m_enemys[i].m_X=rand()%(GAME_WIDTH-m_enemys[i].m_Rect.width());m_enemys[i].m_Y=-m_enemys[i].m_Rect.height();break;}}}
在PlayGame成员函数的timeout信号发送时候,槽函数中首先追加enemyToScene
//敌机出场enemyToScene();
更新敌机坐标,在updatePosition成员函数中追加代码
//敌机坐标计算for(inti=0;iENEMY_NUM;i++){//非空闲敌机更新坐标if(m_enemys[i].m_Free==false){m_enemys[i].updatePosition();}}
绘制敌机,在paintEvent成员函数中追加绘制敌机代码
//绘制敌机for(inti=0;iENEMY_NUM;i++){if(m_enemys[i].m_Free==false){painter.drawPixmap(m_enemys[i].m_X,m_enemys[i].m_Y,m_enemys[i].m_enemy);}}
添加随机数种子
在MainScene.cpp中initScene成员函数里添加随机数种子
//随机数种子srand((unsignedint)time(NULL));//头文件#includectime
运行测试敌机出场效果
10碰撞检测
实现碰撞检测步骤如下:
添加并实现碰撞检测成员函数调用并测试函数10.1添加并实现碰撞检测函数
在MainScene.h中添加新的成员函数
voidcollisionDetection();
在MainScene.cpp中实现该成员函数
voidMainScene::collisionDetection(){//遍历所有非空闲的敌机for(inti=0;iENEMY_NUM;i++){if(m_enemys[i].m_Free){//空闲飞机跳转下一次循环continue;}//遍历所有非空闲的子弹for(intj=0;jBULLET_NUM;j++){if(m_hero.m_bullets[j].m_Free){//空闲子弹跳转下一次循环continue;}//如果子弹矩形框和敌机矩形框相交,发生碰撞,同时变为空闲状态即可if(m_enemys[i].m_Rect.intersects(m_hero.m_bullets[j].m_Rect)){m_enemys[i].m_Free=true;m_hero.m_bullets[j].m_Free=true;}}}}
10.2调用并测试函数
在MainScene.cpp中playGame成员函数里,追加碰撞检测代码
运行查看效果,子弹和敌机碰撞后会同时消失
11爆炸效果
爆炸效果功能实现步骤如下:
创建爆炸文件和类添加爆炸类中的成员函数和成员属性实现成员函数调用并测试效果11.1创建爆炸文件和类
创建Bomb类以及生成对应的文件
创建好后生成bomb.h和bomb.cpp两个文件
11.2爆炸成员函数和成员属性
在config.h中加入爆炸配置数据
#defineBOMB_PATH:/res/bomb-%1.png//爆炸资源图片#defineBOMB_NUM20//爆炸数量#defineBOMB_MAX7//爆炸图片最大索引#defineBOMB_INTERVAL20//爆炸切图时间间隔
在bomb.h中添加如下代码:
#ifndefBOMB_H#defineBOMB_H#includeconfig.h#includeQPixmap#includeQVectorclassBomb{public:Bomb();//更新信息(播放图片下标、播放间隔)voidupdateInfo();public://放爆炸资源数组QVectorQPixmapm_pixArr;//爆炸位置intm_X;intm_Y;//爆炸状态boolm_Free;//爆炸切图的时间间隔intm_Recoder;//爆炸时加载的图片下标intm_index;};#endif//BOMB_H
11.3实现成员函数
Bomb::Bomb(){//初始化爆炸图片数组for(inti=1;i=BOMB_MAX;i++){//字符串拼接,类似:/res/bomb-1.pngQStringstr=QString(BOMB_PATH).arg(i);m_pixArr.push_back(QPixmap(str));}//初始化坐标m_X=0;m_Y=0;//初始化空闲状态m_Free=true;//当前播放图片下标m_index=0;//爆炸间隔记录m_Recoder=0;}voidBomb::updateInfo(){//空闲状态if(m_Free){return;}m_Recoder++;if(m_RecoderBOMB_INTERVAL){//记录爆炸间隔未到,直接return,不需要切图return;}//重置记录m_Recoder=0;//切换爆炸播放图片m_index++;//注:数组中的下标从0开始,最大是6//如果计算的下标大于6,重置为0if(m_indexBOMB_MAX-1){m_index=0;m_Free=true;}}
11.4加入爆炸数组
在MainScene.h中加入爆炸数组成员属性
//爆炸数组Bombm_bombs[BOMB_NUM];
在碰撞检测成员函数中,当发生碰撞时,设置爆炸对象的信息
//播放爆炸效果for(intk=0;kBOMB_NUM;k++){if(m_bombs[k].m_Free){//爆炸状态设置为非空闲m_bombs[k].m_Free=false;//更新坐标m_bombs[k].m_X=m_enemys[i].m_X;m_bombs[k].m_Y=m_enemys[i].m_Y;break;}}
在MainScene.cpp的updatePosition中追加代码
//计算爆炸播放的图片for(inti=0;iBOMB_NUM;i++){if(m_bombs[i].m_Free==false){m_bombs[i].updateInfo();}}
在MainScene.cpp的paintEvent中追加绘制爆炸代码
//绘制爆炸图片for(inti=0;iBOMB_NUM;i++){if(m_bombs[i].m_Free==false){painter.drawPixmap(m_bombs[i].m_X,m_bombs[i].m_Y,m_bombs[i].m_pixArr[m_bombs[i].m_index]);}}
测试,实现爆炸效果
12音效添加
音效添加步骤如下:
添加多媒体模块播放音效12.1添加多媒体模块
在工程文件planeWar.pro中修改代码
QT+=coreguimultimedia
12.2播放音效
在config.h中添加音效的配置路径
#defineSOUND_BACKGROUND:/res/bg.wav#defineSOUND_BOMB:/res/bomb.wav
注:QSound使用时候要包含头文件#include\
在PlayGame中添加背景音乐
//启动背景音乐QSound::play(SOUND_BACKGROUND);
在爆炸时候添加爆炸音
//播放音效QSound::play(SOUND_BOMB);
测试音效
13打包发布
确定环境变量配置好PATH:C:\Qt\Qt5.x.x\5.x.x\mingw53_32\bin在QT中把运行模式切换成release模式,编译。在外层目录中会有release版本的目录.将目录中的rcc二进制资源文件、可执行程序文件(.exe)拷贝到另外一个单独的文件夹中.进入cmd命令模式,切换到可执行程序所在的目录.执行以下命令,将可执行程序所需的库文件拷贝到当前目录:cwindeployqtPlaneWar.exe额外可以将ico图标也拷贝到当前可执行程序所在的目录.启动HMNISEDIT软件,在软件中选择:文件-新建脚本向导,接下来跟着向导操作.为了让安装包安装软件也有快捷方式图标,在生成的脚本里。进行修改:cCreateShortCutDESKTOP\飞机大战.lnkINSTDIR\PlaneWar.exeCreateShortCutDESKTOP\飞机大战.lnkINSTDIR\PlaneWar.exeINSTDIR\app.ico点击菜单栏的NSIs,然后选择编译,在桌面生成安装包.