C++学习教程 QT飞机大战教程(含详细步骤教程一)
1 项目简介
飞机大战是我们大家所熟知的一款小游戏,本教程就是教大家如何制作一款自己的飞机大战
首先我们看一下效果图
玩家控制一架小飞机,然后自动发射子弹,如果子弹打到了飞下来的敌机,则射杀敌机,并且有爆炸的特效
接下来再说明一下案例的需求,也就是我们需要实现的内容
滚动的背景地图飞机的制作和控制子弹的制作和射击敌机的制作碰撞检测爆炸效果音效添加2 创建项目
创建项目步骤如下:
打开Qt跟着向导创建项目基类选择 QWidget空窗口
第一个场景为主场景 MainScene
不带UI界面
2.1 打开Qt
找到你安装的Qt Creator,打开它
如果安装时,没有选择在桌面上建立快捷方式,那么你的Qt软件位置如下
C:qtQt5.x.xToolsQtCreatorbin
在这个路径下找到
qtcreator.exe
双击打开即可
2.2 按照向导创建项目
2.2.1 新建项目
点击菜单 中的文件 -> 新建文件或项目 或者 在首页面中点击New Project
2.2.2 选择模板
模板选择 Application -> Qt Widget Application
2.2.3 项目名称和位置
给项目起个名称以及选中项目要保存的地方
这一步选择后在Kits 构建套件中直接点击下一步即可
2.2.4 类信息
基类选择 QWidget
类名也就是我们第一个窗口场景的名称,这里我起名为
MainScene
代表游戏中的主场景
取消创建界面中的内容
2.2.5 完成创建
在汇总页面中点击完成,我们就迈开了项目的第一步!
3 设置主场景
主场景设置的步骤如下:
添加配置文件,保存游戏中所有配置数据初始化主场景窗口大小、标题3.1 配置文件添加
创建新的头文件为 config.h 主要记录程序中所有的配置数据,方便后期修改
添加窗口宽度、高度的配置信息,依据背景图大小进行设置
/********** 游戏配置数据 **********/#define GAME_WIDTH 512 //宽度#define GAME_HEIGHT 768 //高度#define GAME_TITLE "飞机大战 v1.0" //标题
3.2 主场景基本设置
在mainScene.h中添加新的成员函数initScene 用来初始化游戏场景
voidinitScene();
在mainScene.cpp中实现如下代码
voidMainScene::initScene(){//初始化窗口大小setFixedSize(GAME_WIDTH,GAME_HEIGHT);//设置窗口标题setWindowTitle(GAME_TITLE);}
在构造函数MainScene中调用该函数 initScene
MainScene::MainScene(QWidget*parent):QWidget(parent){//初始化场景initScene();}
测试运行效果如图:
4 资源导入
在主场景中其实还有一个配置项没有实现,也就是窗口左上角的那个图标资源
那么接下来我们将游戏中的资源进行导入并且设置游戏图标
资源导入步骤
生成qrc文件项目同级目录下创建res文件夹并将资源粘贴过来编辑qrc,加入前缀和文件利用qrc生成二进制文件 rccrcc文件放入到debug同级目录下注册二进制文件添加图标资源4.1 qrc文件生成
右键项目,点击添加新文件
选择Qt -> Qt Resource File
资源文件起名 如:res
生成res.qrc文件
4.2 创建res文件夹
项目的同级目录下创建文件夹res,并将准备好的资源粘贴进去
4.3 编辑qrc文件
右键qrc文件,选中Open in Editor
添加前缀为 ' '
添加文件 将res下所有文件选中即可
4.4 qrc生成 rcc二进制文件
由于资源过大,会提示错误:
这个错误也就是“编译器的堆空间不足”。
由于资源文件qrc过大,超出分配的内存范围
因此我们需要利用二进制资源,而生成二进制资源就需要我们刚刚的qrc文件
利用cmd打开终端,定位到res.qrc的目录下,输入命令
rcc-binary.res.qrc-oplane.rcc
4.5 复制rcc文件
将生成好的rcc文件,放入到debug同级目录中一份
4.6 注册二进制文件
在config.h中追加配置数据
#define GAME_RES_PATH "./plane.rcc" //rcc文件路径
在main.cpp中修改代码
#include"mainscene.h"#include
此时,qrc文件已经没用了,删除即可!
最简单的删除方式就是 .pro工程文件中删除代码,与工程无瓜葛
删除以下代码:RESOURCES+= res.qrc
4.7 添加图标资源
配置文件config.h中追加代码
虚拟资源路径语法如下:
" : + 前缀名 + 文件路径 "
#define GAME_ICON ":/res/app.ico"
在mainScene.cpp的 initScene函数中追加代码:
//设置图标资源setWindowIcon(QIcon(GAME_ICON));//加头文件 #include
运行测试:
5 地图滚动
步骤:
创建地图文件和类添加成员函数和成员属性 实现成员函数游戏运行调用定时器启动定时器,监听定时器信号实现游戏循环计算游戏内元素坐标绘制到屏幕中5.1 创建地图文件和类
右键项目,添加新文件
选择C++ -> C++ Class
修改类名为map,点击下一步,直到创建完毕
至此,地图Map的文件和类创建完毕
5.2 地图的成员函数和成员属性
在map.h中添加如下代码
#ifndef MAP_H#define MAP_H#include
5.3 实现成员函数
在config.h中添加新的配置数据
/********** 地图配置数据 **********/#define MAP_PATH ":/res/img_bg_level_1.jpg" //地图图片路径#define MAP_SCROLL_SPEED 2 //地图滚动速度
在map.cpp中实现成员函数
#include"map.h"#include"config.h"Map::Map(){//初始化加载地图对象m_map1.load(MAP_PATH);m_map2.load(MAP_PATH);//设置地图其实y轴坐标m_map1_posY=-GAME_HEIGHT;m_map2_posY=0;//设置地图滚动速度m_scroll_speed=MAP_SCROLL_SPEED;}voidMap::mapPosition(){//处理第一张图片滚动m_map1_posY+=MAP_SCROLL_SPEED;if(m_map1_posY>=0){m_map1_posY=-GAME_HEIGHT;}//处理第二张图片滚动m_map2_posY+=MAP_SCROLL_SPEED;if(m_map2_posY>=GAME_HEIGHT){m_map2_posY=0;}}
5.4 定时器添加
在mainScene.h中添加新的定时器对象
QTimerm_Timer;
在 config.h中添加 屏幕刷新间隔
#define GAME_RATE 10 //刷新间隔,帧率 单位毫秒
在MainScene.cpp的initScene中追加代码
//定时器设置m_Timer.setInterval(GAME_RATE);
5.5 启动定时器实现地图滚动
在MainScene.h中添加新的成员函数以及成员对象
//启动游戏 用于启动定时器对象voidplayGame();//更新坐标voidupdatePosition();//绘图事件voidpaintEvent(QPaintEvent*event);//地图对象Mapm_map;
在MainScene.cpp中实现成员函数
voidMainScene::playGame(){//启动定时器m_Timer.start();//监听定时器connect(&m_Timer,&QTimer::timeout,[=](){//更新游戏中元素的坐标updatePosition();//重新绘制图片update();});}voidMainScene::updatePosition(){//更新地图坐标m_map.mapPosition();}voidMainScene::paintEvent(QPaintEvent*event){QPainterpainter(this);//绘制地图painter.drawPixmap(0,m_map.m_map1_posY,m_map.m_map1);painter.drawPixmap(0,m_map.m_map2_posY,m_map.m_map2);}
测试运行游戏,实现地图滚动
6 英雄飞机
步骤如下:
创建英雄文件和类添加成员函数和成员属性实现成员函数创建飞机对象并显示拖拽飞机6.1 创建英雄文件和类
创建HeroPlane类以及生成对应的文件
和创建地图的步骤一样,这里就不在详细截图了
创建好后生成HeroPlane.h 和 HeroPlane.cpp两个文件
6.2 飞机的成员函数和成员属性
在HeroPlane.h中添加代码
classHeroPlane{public:HeroPlane();//发射子弹voidshoot();//设置飞机位置voidsetPosition(intx,inty);public://飞机资源 对象QPixmapm_Plane;//飞机坐标intm_X;intm_Y;//飞机的矩形边框QRectm_Rect;};
6.3 成员函数实现
这里飞机有个发射子弹的成员函数,由于我们还没有做子弹
因此这个成员函数先写成空实现即可
在config.h中追加飞机配置参数
/********** 飞机配置数据 **********/#define HERO_PATH ":/res/hero2.png"
heroPlane.cpp中实现成员函数代码:
#include"heroplane.h"#include"config.h"HeroPlane::HeroPlane(){//初始化加载飞机图片资源m_Plane.load(HERO_PATH);//初始化坐标m_X=GAME_WIDTH*0.5-m_Plane.width()*0.5;m_Y=GAME_HEIGHT-m_Plane.height();//初始化矩形框m_Rect.setWidth(m_Plane.width());m_Rect.setHeight(m_Plane.height());m_Rect.moveTo(m_X,m_Y);}voidHeroPlane::setPosition(intx,inty){m_X=x;m_Y=y;m_Rect.moveTo(m_X,m_Y);}voidHeroPlane::shoot(){}
6.4 创建飞机对象并显示
在MainScene.h中追加新的成员属性
//飞机对象HeroPlanem_hero;
在MainScene.cpp的paintEvent中追加代码
//绘制英雄painter.drawPixmap(m_hero.m_X,m_hero.m_Y,m_hero.m_Plane);
测试飞机显示到屏幕中
6.5 拖拽飞机
在MainScene.h中添加鼠标移动事件
//鼠标移动事件voidmouseMoveEvent(QMouseEvent*event);
重写鼠标移动事件
voidMainScene::mouseMoveEvent(QMouseEvent*event){intx=event->x()-m_hero.m_Rect.width()*0.5;//鼠标位置 - 飞机矩形的一半inty=event->y()-m_hero.m_Rect.height()*0.5;//边界检测if(x<=0){x=0;}if(x>=GAME_WIDTH-m_hero.m_Rect.width()){x=GAME_WIDTH-m_hero.m_Rect.width();}if(y<=0){y=0;}if(y>=GAME_HEIGHT-m_hero.m_Rect.height()){y=GAME_HEIGHT-m_hero.m_Rect.height();}m_hero.setPosition(x,y);}
测试飞机可以拖拽
7 子弹制作
制作步骤如下:
创建子弹文件和类添加子弹类中的成员函数和成员属性实现成员函数测试子弹7.1 创建子弹文件和类
创建Bullet类以及生成对应的文件
创建好后生成bullet.h 和 bullet.cpp两个文件
7.2 子弹的成员函数和成员属性
在Bullet.h中添加代码
#ifndef BULLET_H#define BULLET_H#include"config.h"#include
7.3 子弹类成员函数实现
在config.h中追加子弹配置信息
/********** 子弹配置数据 **********/#define BULLET_PATH ":/res/bullet_11.png" //子弹图片路径#define BULLET_SPEED 5 //子弹移动速度
在bullet.cpp中实现成员函数,代码如下:
#include"bullet.h"Bullet::Bullet(){//加载子弹资源m_Bullet.load(BULLET_PATH);//子弹坐标 初始坐标可随意设置,后期会重置m_X=GAME_WIDTH*0.5-m_Bullet.width()*0.5;m_Y=GAME_HEIGHT;//子弹状态m_Free=true;//子弹速度m_Speed=BULLET_SPEED;//子弹矩形框m_Rect.setWidth(m_Bullet.width());m_Rect.setHeight(m_Bullet.height());m_Rect.moveTo(m_X,m_Y);}voidBullet::updatePosition(){//如果子弹是空闲状态,不需要坐标计算//玩家飞机可以控制子弹的空闲状态为falseif(m_Free){return;}//子弹向上移动m_Y-=m_Speed;m_Rect.moveTo(m_X,m_Y);if(m_Y<=-m_Rect.height()){m_Free=true;}}
7.4 测试子弹
子弹本身应该由飞机发射,测试阶段我们写一段辅助代码,看看效果即可
测试过后,这些代码可以删除掉
在MainScene.h中添加测试代码
//测试子弹代码Bullettemp_bullet;
在MainScene.cpp中的updatePosition里添加测试代码
//测试子弹代码temp_bullet.m_Free=false;temp_bullet.updatePosition();
在MainScene.cpp中的paintEvent里添加测试代码
//测试子弹代码painter.drawPixmap(temp_bullet.m_X,temp_bullet.m_Y,temp_bullet.m_Bullet);
运行程序,此时会有一发子弹从屏幕中射出
测试完毕后,测试代码删除或注释即可