前言:最近学习Qt时,当做项目练手,把以前小学期要做的飞机大战又重新做了一遍。以前的时候是用MFC做的,现在改到了用Qt界面来做。不得不说,Qt确实是要好用多了。在此记录,方便自己,希望也能有助于大家。

飞机大战本身并不是很难,这里就介绍我实现过程中的重点了,主要分为以下几个部分:
1、类模型的建立
2、飞机如何移动
3、碰撞检测
4、爆炸动画的实现
5、飞机图片透明效果的实现
6、背景图的移动
7、游戏状态的转换

以下带着源码,分别介绍。

一、类模型的建立
学习完C++之后,飞机大战确实是一个比较好的练手项目,可以检验咱C++这个对象到底“谈”妥了没。 惭愧的说,到现在,我的面向对象思想建立的还是不够完善。在这个项目中,还没有体现到很深层次的面向对象的思路。以下是我简历的UML类图:
其中:
(1)、VObj类:这是我一开始抽象出来的物体类,就像Qt中的Object一样,但后来发现它把Plane类和Bullet类要做的工作都完成了,导致Plane和Bullet没什么可干的。这里完成的工作主要是物体的移动和判断物体是否消失。
(2)、Plane类和Bullet类:几乎是空的。为了与后面的类衔接合理些,也就没去删掉这个中间层。
(3)、MyPlane类:这是继承Plane的我方战机类。其中主要飞机的移动与发射子弹。稍微要注意点是这个类中含有MyBullet类的指针,这是为了发射子弹之用。
(4)、EnemyFIsh类:继承Plane类的敌方杂鱼类。其工作主要由上层的父类完成了,这里也几乎是空的。
(5)、MyBullet类:这是继承Bullet的子类。除了完成一些必要的工作,也几乎是空的。
(6)、Explosion类:爆炸类。这个类是一个独立的类,和其他的类都没有太大关系(和Widge类有点关系)。它主要是完成爆炸的一些工作,如加载爆炸的一系列图片,切换爆炸的图片,设置爆炸的位置等等。
(7)、Widget类:这个类是一个综合的类。从类图中也可以看出来,它和MyPlane、Explosion、EnemyFish都有关系。这个类继承了Qt的Object,通过重绘事件、键盘事件、定时器事件,把以上各类综合起来以达到飞机大战的效果。整个工程80%的工作都这这个类中,后面要介绍的其他几个重点也大部分都是在这个类中实现的。(说句废话,也正是从这个类中,可以看出来我的面向对象的设计理解的还不够深,还不能够设计出耦合性更小,代码利用率更高的程序。)

二、飞机如何移动
飞机时如何移动的呢?这里用了比较低级的做法,即通过检测按键事件,判断飞机的移动方向,然后在定时器事件中移动飞机,最后在重绘事件中不断绘制飞机。这样就达到了飞机移动的效果。同理,子弹的移动和敌方杂鱼机的移动也是这个原理。(这里应该可以用Qt更高级的动画框架来实现,目前我还没学会,嘿嘿)
主要的代码如下:

void Widget::keyPressEvent(QKeyEvent *event)
{if(state == RUNNING_STATE)          //第二个阶段时{int fly_dir = 0;//判断按下哪个按键,并打上标记if(event->key() == Qt::Key_Up)fly_dir = FLY_UP;if(event->key() == Qt::Key_Down)fly_dir = FLY_DOWN;if(event->key() == Qt::Key_Left)fly_dir = FLY_LEFT;if(event->key() == Qt::Key_Right)fly_dir = FLY_RIGHT;myPlane->SetFlyDir(fly_dir,true);  //给指定的方向打上标记if(event->key() == Qt::Key_Space){myPlane->FireBull();        //发射子弹}}else{if(event->key() == Qt::Key_Return){state = RUNNING_STATE;Init();}}}//定时器事件:主要用于移动飞机;判断战机和敌机、敌机和子弹是否发生碰撞;增加敌机数量;显示爆炸(这里只有定时器的一部分代码)
void Widget::timerEvent(QTimerEvent *event)
{if(event->timerId() == timer1)  //移动飞机和子弹{//移动我方战机for(int i = 1;i<=4;++i){if(myPlane->GetFLyDir(i))       //上下左右:对应1 2 3 4myPlane->Move(i);}//移动子弹QLinkedList<MyBullet*>::iterator iter_bul;for(iter_bul = myPlane->my_bulles.begin();iter_bul!=myPlane->my_bulles.end();++iter_bul){MyBullet *temp_bul = *iter_bul;temp_bul->Move(-1);}//移动敌方杂鱼机QLinkedList<EnemyFish*>::iterator iter_fish;for(iter_fish = fish_list.begin();iter_fish != fish_list.end();++iter_fish){EnemyFish * temp_fish = *iter_fish;temp_fish->Move(0);}this->update();}}//重绘事件:
void Widget::paintEvent(QPaintEvent *event)
{QPainter painter;painter.begin(this);if(state == RUNNING_STATE){ui->label_life->setText(QString::number(myPlane->GetLife()));ui->label_sco->setText(QString::number(myPlane->GetScore()));//绘制动态背景painter.drawPixmap(0,back_spe,back);painter.drawPixmap(0,back_spe-back.height(),back);//绘制我方飞机painter.drawPixmap(myPlane->pos,myPlane->img);//绘制敌机foreach(EnemyFish *temp_fish,fish_list)painter.drawPixmap(temp_fish->pos,temp_fish->img);//绘制我方子弹foreach (MyBullet *temp_bul, myPlane->my_bulles)painter.drawPixmap(temp_bul->pos,temp_bul->img);//绘制爆炸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]));}}else{painter.drawPixmap(0,0,back);if(state == END_STATE){ui->label_life->setText(QString::number(myPlane->GetLife()));ui->label_sco->setText(QString::number(myPlane->GetScore()));}}painter.end();
}

这里还需要注意一点的是:在按键事件中不能直接移动飞机,而应该做一个标志位,然后在定时器中再进行移动,否则不能同时相应两个按键,比如同时按下左和上,飞机向左上方飞。

三、碰撞检测
何为碰撞检测?即在游戏中判断飞机是否和敌机发生碰撞,飞机的子弹是否和敌机发生碰撞(即是否攻击到敌机)。在这里,基本的原理是判断两个对象(飞机和敌机、敌机和子弹)矩形(即图像所占的空间)是否有交叉,如果有交叉,即发生了碰撞。使用的是QRect::intersects()方法。主要代码如下:

 else if(event->timerId() == timer2)     //判断是否发生碰撞{QLinkedList<EnemyFish*>::iterator iter;QLinkedList<MyBullet*>::iterator iter_bul;bool IsAttacked = false;bool IsCon = false;for(iter = fish_list.begin();iter!=fish_list.end();++iter)      //遍历敌方所有杂鱼{EnemyFish *temp_fish = *iter;IsAttacked = false;     //初始未被攻击QRect temp(temp_fish->pos,QSize(temp_fish->img.width(),temp_fish->img.height()));for(iter_bul = myPlane->my_bulles.begin();iter_bul !=myPlane->my_bulles.end();++iter_bul)  //遍历我方所有子弹{MyBullet *temp_bul = *iter_bul;QRect temp_rec(temp_bul->pos,QSize(temp_bul->img.width(),temp_bul->img.height()));IsAttacked = temp.intersects(temp_rec);       //判断是否敌机是否受到我方子弹攻击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;}else{if(temp_bul->IsDisappear() == true){myPlane->my_bulles.removeOne(*iter_bul);      //子弹消失,移除子弹delete temp_bul;}}}if(IsAttacked == false){//判断我方战机是否碰撞到敌方战机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;}else{if(temp_fish->IsDisappear() == true){fish_list.removeOne(*iter);        //敌机移除屏幕,删除敌机delete temp_fish;}}}}back_spe= (back_spe+1)%back.height();   //背景图片移动}

具体来说,就是遍历子弹列表和敌机列表,在两层循环里判断每个子弹是否和敌机列表中的敌机发生碰撞。判断战机和敌机是否发生碰撞也是这个原理。(总的来说,我是感觉这种方式有点low。Qt的高级图形视图框架里有碰撞检测机制,可以运用到这里,图形视图框架,我弄的还不是很熟,也就没采用了)。

今天,先写到这儿吧。有点多,剩下的下次在写吧。在这儿,先上张图:

Qt5实现飞机大战1.0(上)相关推荐

  1. 码上飞机大战v1.0.8

    1.新增积分兑换实物功能 2.新增兑换兑换码功能 3.新增跳转小程序功能 4.新增积分显示列表 5.新增游戏记录列表

  2. 关于Unity的入门游戏飞机大战的开发(上)

    每个组件都是一个类的实例,要获得某个组件,要先创建一个同类型的组件类实例,然后把实例传引用过去,就可以对想要的组件实例进行操作. 做游戏一般创建一个逻辑节点,里面只管逻辑,再创建一个动画节点,里面有好 ...

  3. QT阶段项目——飞机大战1.0

    附代码:链接:https://pan.baidu.com/s/1zItNTLnB4QkLuSlVgsd-gQ?pwd=rhy2 提取码:rhy2 一.菜单界面 1.菜单类 class menu: pu ...

  4. tina -飞机大战6.0

    import random import pygame import sys import plane import enemydef key_control(hero):# event 事件:电脑监 ...

  5. tina -飞机大战4.0

    import pygame import sys import plane import enemydef key_control(hero):# event 事件:电脑监控们对电脑的每一次操作,包括 ...

  6. 飞机大战小游戏1.0版本

    小时候大家应该都玩过飞机大战吧,这就是仿的一个飞机大战,但是没有写的很全,只能玩一次,死掉之后需要刷新页面玩第二次,话不说多,上代码: 初始页面: 整个的html代码还是很少,如下: <div ...

  7. python 入门实战改进B站小甲鱼飞机大战增强版4.0

    效果: 资源包下载地址:https://download.csdn.net/download/m0_50944918/13977863 部分代码观礼: import pygame import sys ...

  8. 游戏角色坐标的保存间隔_使用C++编写飞机大战游戏【手把手教程】

    友情地提示本文较长,建议保存,慢慢学学.可以直接观看视频教程. C++干大事系列之游戏篇:Qt飞机大战​yun.itheima.com 1.项目简介 飞机大战是我们大家所熟知的一款小游戏,本教程就是教 ...

  9. 西瓜大战java_Java中的线程及(简单飞机大战)实现

    在讲到线程之前我们先聊一下程序,进程,线程这三者的概念: 程序是指为了实现特定目标或解决特定问题而用计算机语言编写的命令序列的集合. 程序存储在磁盘上,由一系列的文件+数据组成. 进程:程序运行起来之 ...

最新文章

  1. 爬虫抓取页面数据原理(php爬虫框架有很多 )
  2. ReactOS 0.4.11 发布,Windows 系统的开源替代方案
  3. MATLAB基本操作(四):结构体struct元胞数组cell
  4. Flow Problem
  5. python在租房过程中的应用
  6. 『软件测试2』 关于黑盒测试和测试用例的基础知识
  7. Caused by: org.springframework.boot.web.server.PortInUseException: Port 8081 is already in use 端口占用
  8. Pandoc提供二进制分发包了
  9. python学习if语句_python学习之if语句
  10. Mozilla Firefox 7.0 发布
  11. 使用Adorner显示WPF控件的边界点
  12. 最详细的JavaScript教程(高级篇),深入学习JavaScript
  13. CF55D-Beautiful numbers【数位dp】
  14. BT656与BT1120的区别
  15. java上传图片压缩大小
  16. Oracle重建索引
  17. Spark SQL的自定义函数UDF
  18. 1428D - Bouncing Boomerangs(思维+构造+贪心)
  19. 证件照人像与背景分离(Pythoncv)
  20. 【有利可图网】PS实战系列:果汁喷溅的效果,你知道是怎么做的吗?

热门文章

  1. 学习笔记之Windows基础
  2. 1.0 Android平台概述
  3. 【手把手教你学习51单片机】74HC138 三八译码器的应用
  4. Linux下通过mdadm进行软raid设置(rhel6.0)
  5. WPS如何双面打印文件呢
  6. ESP8266 RC522
  7. FPGA入门(FPGA结构、Verilog编程基础)
  8. FALSE/TRUE与false/true的区别
  9. intel android haxm,使用Intel HAXM为 Android模拟器加速
  10. Android app 性能测试以及专项测试