飛機大戰_Qt製作
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 主要記錄程序中所有的配置數據,方便後期修改
添加窗口寬度、高度的配置信息,依據背景圖大小進行設置
<code>/********** 遊戲配置數據 **********/
#define GAME_WIDTH 512 //寬度
#define GAME_HEIGHT 768 //高度
#define GAME_TITLE "飛機大戰 v1.0" //標題
/<code>
3.2 主場景基本設置
在mainScene.h中添加新的成員函數initScene 用來初始化遊戲場景
<code>void initScene();
/<code>
在mainScene.cpp中實現如下代碼
<code>void MainScene::initScene()
{
//初始化窗口大小
setFixedSize(GAME_WIDTH,GAME_HEIGHT);
//設置窗口標題
setWindowTitle(GAME_TITLE);
}
/<code>
在構造函數MainScene中調用該函數 initScene
<code>MainScene::MainScene(QWidget *parent)
: QWidget(parent)
{
//初始化場景
initScene();
}
/<code>
測試運行效果如圖:
4 資源導入
在主場景中其實還有一個配置項沒有實現,也就是窗口左上角的那個圖標資源
那麼接下來我們將遊戲中的資源進行導入並且設置遊戲圖標
資源導入步驟
- 生成qrc文件
- 項目同級目錄下創建res文件夾並將資源粘貼過來
- 編輯qrc,加入前綴和文件
- 利用qrc生成二進制文件 rcc
- rcc文件放入到debug同級目錄下
- 註冊二進制文件
- 添加圖標資源
4.1 qrc文件生成
右鍵項目,點擊添加新文件
選擇Qt -> Qt Resource File
資源文件起名 如:res
生成res.qrc文件
4.2 創建res文件夾
項目的同級目錄下創建文件夾res,並將準備好的資源粘貼進去
右鍵qrc文件,選中Open in Editor
添加前綴為 '' \\ ''
添加文件 將res下所有文件選中即可
4.4 qrc生成 rcc二進制文件
由於資源過大,會提示錯誤:
這個錯誤也就是“編譯器的堆空間不足”。
由於資源文件qrc過大,超出分配的內存範圍
因此我們需要利用二進制資源,而生成二進制資源就需要我們剛剛的qrc文件
利用cmd打開終端,定位到res.qrc的目錄下,輸入命令
<code>rcc -binary .\\res.qrc -o plane.rcc
/<code>
4.5 複製rcc文件
將生成好的rcc文件,放入到debug同級目錄中一份
4.6 註冊二進制文件
在config.h中追加配置數據
<code>#define GAME_RES_PATH "./plane.rcc" //rcc文件路徑
/<code>
在main.cpp中修改代碼
<code>#include "mainscene.h"
#include <qapplication>
#include <qresource>
#include "config.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//註冊外部的二進制資源文件
QResource::registerResource(GAME_RES_PATH);
MainScene w;
w.show();
return a.exec();
}
/<qresource>/<qapplication>/<code>
此時,qrc文件已經沒用了,刪除即可!
最簡單的刪除方式就是 .pro工程文件中刪除代碼,與工程無瓜葛
<code>刪除以下代碼:
RESOURCES += \\
res.qrc
/<code>
4.7 添加圖標資源
配置文件config.h中追加代碼
虛擬資源路徑語法如下:
" : + 前綴名 + 文件路徑 "
<code>#define GAME_ICON ":/res/app.ico"
/<code>
在mainScene.cpp的 initScene函數中追加代碼:
<code>//設置圖標資源
setWindowIcon(QIcon( GAME_ICON)); //加頭文件 #include <qicon>
/<qicon>/<code>
運行測試:
5 地圖滾動
步驟:
- 創建地圖文件和類
- 添加成員函數和成員屬性 實現成員函數
- 遊戲運行調用定時器
- 啟動定時器,監聽定時器信號實現遊戲循環
- 計算遊戲內元素座標
- 繪製到屏幕中
5.1 創建地圖文件和類
右鍵項目,添加新文件
選擇C++ -> C++ Class
修改類名為map,點擊下一步,直到創建完畢
至此,地圖Map的文件和類創建完畢
5.2 地圖的成員函數和成員屬性
在map.h中添加如下代碼
<code>#ifndef MAP_H
#define MAP_H
#include <qpixmap>
class Map
{
public:
//構造函數
Map();
//地圖滾動座標計算
void mapPosition();
public:
//地圖圖片對象
QPixmap m_map1;
QPixmap m_map2;
//地圖Y軸座標
int m_map1_posY;
int m_map2_posY;
//地圖滾動幅度
int m_scroll_speed;
};
#endif // MAP_H
/<qpixmap>/<code>
5.3 實現成員函數
在config.h中添加新的配置數據
<code>/********** 地圖配置數據 **********/
#define MAP_PATH ":/res/img_bg_level_1.jpg" //地圖圖片路徑
#define MAP_SCROLL_SPEED 2 //地圖滾動速度
/<code>
在map.cpp中實現成員函數
<code>#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;
}
void Map::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;
}
}
/<code>
5.4 定時器添加
在mainScene.h中添加新的定時器對象
<code>QTimer m_Timer;
/<code>
在 config.h中添加 屏幕刷新間隔
<code>#define GAME_RATE 10 //刷新間隔,幀率 單位毫秒
/<code>
在MainScene.cpp的initScene中追加代碼
<code>//定時器設置
m_Timer.setInterval(GAME_RATE);
/<code>
5.5 啟動定時器實現地圖滾動
在MainScene.h中添加新的成員函數以及成員對象
<code>//啟動遊戲 用於啟動定時器對象
void playGame();
//更新座標
void updatePosition();
//繪圖事件
void paintEvent(QPaintEvent *event);
//地圖對象
Map m_map;
/<code>
在MainScene.cpp中實現成員函數
<code>void MainScene::playGame()
{
//啟動定時器
m_Timer.start();
//監聽定時器
connect(&m_Timer,&QTimer::timeout,[=](){
//更新遊戲中元素的座標
updatePosition();
//重新繪製圖片
update();
});
}
void MainScene::updatePosition()
{
//更新地圖座標
m_map.mapPosition();
}
void MainScene::paintEvent(QPaintEvent *event)
{
QPainter painter(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);
}
/<code>
測試運行遊戲,實現地圖滾動
6 英雄飛機
步驟如下:
- 創建英雄文件和類
- 添加成員函數和成員屬性
- 實現成員函數
- 創建飛機對象並顯示
- 拖拽飛機
6.1 創建英雄文件和類
創建HeroPlane類以及生成對應的文件
和創建地圖的步驟一樣,這裡就不在詳細截圖了
創建好後生成HeroPlane.h 和 HeroPlane.cpp兩個文件
6.2 飛機的成員函數和成員屬性
在HeroPlane.h中添加代碼
<code>class HeroPlane
{
public:
HeroPlane();
//發射子彈
void shoot();
//設置飛機位置
void setPosition(int x, int y);
public:
//飛機資源 對象
QPixmap m_Plane;
//飛機座標
int m_X;
int m_Y;
//飛機的矩形邊框
QRect m_Rect;
};
/<code>
6.3 成員函數實現
這裡飛機有個發射子彈的成員函數,由於我們還沒有做子彈
因此這個成員函數先寫成空實現即可
在config.h中追加飛機配置參數
<code>/********** 飛機配置數據 **********/
#define HERO_PATH ":/res/hero2.png"
/<code>
heroPlane.cpp中實現成員函數代碼:
<code>#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);
}
void HeroPlane::setPosition(int x, int y)
{
m_X = x;
m_Y = y;
m_Rect.moveTo(m_X,m_Y);
}
void HeroPlane::shoot()
{
}
/<code>
6.4 創建飛機對象並顯示
在MainScene.h中追加新的成員屬性
<code>//飛機對象
HeroPlane m_hero;
/<code>
在MainScene.cpp的paintEvent中追加代碼
<code>//繪製英雄
painter.drawPixmap(m_hero.m_X,m_hero.m_Y,m_hero.m_Plane);
/<code>
測試飛機顯示到屏幕中
6.5 拖拽飛機
在MainScene.h中添加鼠標移動事件
<code>//鼠標移動事件
void mouseMoveEvent(QMouseEvent *event);
/<code>
重寫鼠標移動事件
<code>void MainScene::mouseMoveEvent(QMouseEvent *event)
{
int x = event->x() - m_hero.m_Rect.width()*0.5; //鼠標位置 - 飛機矩形的一半
int y = 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);
}
/<code>
測試飛機可以拖拽
閱讀更多 傳智播客官方賬號 的文章