1 項目簡介
飛機大戰是我們大家所熟知的一款小遊戲,本教程就是教大家如何製作一款自己的飛機大戰
首先我們看一下效果圖
玩家控制一架小飛機,然後自動發射子彈,如果子彈打到了飛下來的敵機,則射殺敵機,並且有爆炸的特效
接下來再說明一下案例的需求,也就是我們需要實現的內容
滾動的背景地圖飛機的製作和控制子彈的製作和射擊敵機的製作碰撞檢測爆炸效果音效添加2 創建項目
創建項目步驟如下:
打開Qt跟著嚮導創建項目基類選擇 QWidget空窗口
第一個場景為主場景 MainScene
不帶UI界面
2.1 打開Qt
找到你安裝的Qt Creator,打開它
如果安裝時,沒有選擇在桌面上建立快捷方式,那麼你的Qt軟體位置如下
C:\qt\Qt5.x.x\Tools\QtCreator\bin
在這個路徑下找到
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<QApplication>#include<QResource>#include"config.h"intmain(intargc,char*argv[]){QApplicationa(argc,argv);//註冊外部的二進位資源文件QResource::registerResource(GAME_RES_PATH);MainScenew;w.show();returna.exec();}
此時,qrc文件已經沒用了,刪除即可!
最簡單的刪除方式就是 .pro工程文件中刪除代碼,與工程無瓜葛
刪除以下代碼:RESOURCES+= \ res.qrc
4.7 添加圖標資源
配置文件config.h中追加代碼
虛擬資源路徑語法如下:
" : + 前綴名 + 文件路徑 "
#define GAME_ICON ":/res/app.ico"
在mainScene.cpp的 initScene函數中追加代碼:
//設置圖標資源setWindowIcon(QIcon(GAME_ICON));//加頭文件 #include <QIcon>
運行測試:
5 地圖滾動
步驟:
創建地圖文件和類添加成員函數和成員屬性 實現成員函數遊戲運行調用定時器啟動定時器,監聽定時器信號實現遊戲循環計算遊戲內元素坐標繪製到屏幕中5.1 創建地圖文件和類
右鍵項目,添加新文件
選擇C++ -> C++ Class
修改類名為map,點擊下一步,直到創建完畢
至此,地圖Map的文件和類創建完畢
5.2 地圖的成員函數和成員屬性
在map.h中添加如下代碼
#ifndef MAP_H#define MAP_H#include<QPixmap>classMap{public://構造函數Map();//地圖滾動坐標計算voidmapPosition();public://地圖圖片對象QPixmapm_map1;QPixmapm_map2;//地圖Y軸坐標intm_map1_posY;intm_map2_posY;//地圖滾動幅度intm_scroll_speed;};#endif // MAP_H
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<QPixmap>classBullet{public:Bullet();//更新子彈坐標voidupdatePosition();public://子彈資源對象QPixmapm_Bullet;//子彈坐標intm_X;intm_Y;//子彈移動速度intm_Speed;//子彈是否閒置boolm_Free;//子彈的矩形邊框(用於碰撞檢測)QRectm_Rect;};#endif // BULLET_H
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);
運行程序,此時會有一發子彈從屏幕中射出
測試完畢後,測試代碼刪除或注釋即可