飞机大战
程序员文章站
2022-07-13 08:34:54
...
飞机大战初步功能实现:
1.开始菜单界面(可更改地图)
2.游戏界面(移动飞机、发射子弹、击毁敌机、撞毁)
3.结束界面(可返回开始菜单)
功能截图如下:
程序代码如下:
项目工程组成
mainscene.h:
#ifndef MAINSCENE_H
#define MAINSCENE_H
#include <QWidget>
#include"config.h"
#include<QIcon>
#include<QTimer>
#include<QPaintEvent>
#include"map.h"
#include<QPainter>
#include"heroplane.h"
#include<QMouseEvent>
#include"bullet.h"
#include"enemyplane.h"
#include"bomb.h"
#include<QMessageBox>
#include<QMutex> //暂停
#include<QThread>
#include"mythread.h"
#include"dickmenu.h"
#include<QDebug>
class mainScene : public QWidget
{
Q_OBJECT
public:
mainScene(QWidget *parent = nullptr);
~mainScene();
void InitScene();
QMutex m_mutex; //互斥量
QTimer m_timer;
bool StartPaintBullet=true; //是否绘制子弹 本机撞毁后
bool StartCheckEnemy=true; //是否检测子弹与敌机碰撞 本机撞毁后
//启动游戏
void playGame();
//更新游戏坐标
void updatePosition();
//绘制到屏幕中 函数名不可更改
void paintEvent(QPaintEvent *);
//地图对象
map M_map;
//飞机对象
HeroPlane hero_plane;
//重写鼠标移动事件 函数名不可更改
void mouseMoveEvent(QMouseEvent *);
//捕捉键盘事件
//void keyPressEvent(QKeyEvent *event);
//敌机出场
void enemyToscreen();
//敌机数组
EnemyPlane m_enemyplanes[7];
EnemyPlane m_enemies[ENEMY_NUM];
int enemy_recorder;
//碰撞检测
void collisionDetection();
//爆炸数组
Bomb m_bombs[Bomb_NUM];
MyThread *thread;
// void Done();
signals:
void ReturnMenu();
};
#endif // MAINSCENE_H
heroplane.h:
#ifndef HEROPLANE_H
#define HEROPLANE_H
#include<QPixmap>
#include<QRect>
#include"bullet.h"
class HeroPlane
{
public:
HeroPlane();
//发射子弹
void shoot();
//设置飞机位置
void setPlanePosition(int x,int y);
bool hero_free;
//飞机资源 对象
QPixmap m_Plane;
//飞机坐标
int plane_x;
int plane_y;
//飞机矩形边框
QRect plane_rect;
bullet m_bullets[bullet_num];//弹夹
int m_recorder; //发射间隔记录
};
#endif // HEROPLANE_H
enemyplane.h:
#ifndef ENEMYPLANE_H
#define ENEMYPLANE_H
#include<QPixmap>
#include"config.h"
#include<QVector>
class EnemyPlane
{
public:
EnemyPlane();
//更新坐标
void updateEnemyPosition();
//敌机资源对象
QPixmap m_enemy;
//位置
int enemy_x;
int enemy_y;
//敌机矩形边框
QRect enemy_rect;
//是否空闲
bool enemy_free;
//敌机速度
int enemy_speed;
};
#endif // ENEMYPLANE_H
startgame.h:
#ifndef STARTGAME_H
#define STARTGAME_H
#include<QString>
#include <QDialog>
#include"mainscene.h"
namespace Ui {
class StartGame;
}
class StartGame : public QDialog
{
Q_OBJECT
public:
explicit StartGame(QWidget *parent = nullptr);
~StartGame();
QString MapStyle=":/new/prefix1/res/img_bg_level_1.jpg";
QString EnemyPlaneStyle=QString(":/new/prefix1/res/img-plane_%1.png").arg(rand()%10);
void changeMap();
public slots:
void on_pushButtonStart_clicked();
void on_pushButtonStart_Design_clicked();
void on_pushButtonStart_Exit_clicked();
void on_pushButtonSureDeSign_clicked();
private slots:
private:
Ui::StartGame *ui;
};
#endif // STARTGAME_H
bomb.h:
#ifndef BOMB_H
#define BOMB_H
#include<QVector>
#include<QPixmap>
#include"config.h"
class Bomb
{
public:
Bomb();
void updateInfo();//更新信息
//放爆炸资源数组
QVector<QPixmap>m_pixArr;
//爆炸位置
int Bomb_x;
int Bomb_y;
//爆炸状态
bool Bomb_free;
//爆炸时间间隔
int Bomb_recorder;
//爆炸时加载的图片下标
int bombing_index;
};
#endif // BOMB_H
bullet.h:
#ifndef BULLET_H
#define BULLET_H
#include"config.h"
#include<QPixmap>
class bullet
{
public:
bullet();
//更新子弹坐标
void updateBulletPosition();
//子弹资源对象
QPixmap m_bullet;
//子弹坐标
int bullet_x;
int bullet_y;
//子弹移动速度
int bullet_speed;
//子弹是否闲置
bool bullet_free;
//子弹矩形边框
QRect bullet_rect;
};
#endif // BULLET_H
dickmenu.h:
#ifndef DICKMENU_H
#define DICKMENU_H
#include"startgame.h"
#include <QDialog>
namespace Ui {
class DickMenu;
}
class DickMenu : public QDialog
{
Q_OBJECT
public:
explicit DickMenu(QWidget *parent = nullptr);
~DickMenu();
public slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::DickMenu *ui;
signals:
void returnWindow();
};
#endif // DICKMENU_H
map:
#ifndef MAP_H
#define MAP_H
#include<QPixmap>
#include <QWidget>
class map
{
//Q_OBJECT
public:
map();
//地图滚动坐标计算
void mapPosition();
//地图图片对象
QPixmap m_map1;
QPixmap m_map2;
//地图Y轴坐标
int m_map1_posY;
int m_map2_posY;
//地图滚动幅度
int m_scroll_speed;
};
#endif // MAP_H
mythread.h:
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
void dicked();
protected:
void run();
signals:
void isDone();
};
#endif // MYTHREAD_H
config.h:
#ifndef CONFIG_H
#define CONFIG_H
//游戏数据
#define GAME_Width 512 //宽度
#define GAME_Heigth 768 //高度
#define GAME_Title "飞机大战" //窗口标题
#define GAME_ICON ":/new/prefix1/res/app.ico"
#define GAME_Rate 10 //定时器刷新间隔 毫秒
//地图配置数据
#define Map_Path ":/new/prefix1/res/img_bg_level_2.jpg" //地图背景图
#define Map_Scroll_Speed 2 //地图滚动速度
//飞机配置数据
#define Plane_Model ":/new/prefix1/res/hero.png"
//子弹数据
#define bullet_model ":/new/prefix1/res/bullet_11.png" //子弹模型
#define BULLET_SPEED 5 //子弹速度
#define bullet_num 30 //子弹数量
#define bullet_interval 20 //子弹发射间隔
//敌机数据
#define enemyplane_model ":/new/prefix1/res/img-plane_7.png"
#define ENEMY_SPEED 3
#define ENEMY_NUM 50
#define ENEMY_INTERVAL 30
//爆炸效果
#define Bomb_model ":/new/prefix1/res/bomb-%1.png"
#define Bomb_NUM 20 //爆炸数量
#define Bomb_max 7 //爆炸图片最大索引
#define Bomb_Interval 10//爆炸切图时间间隔
//#define BombHero 1000
//音效
#define Sound_backgroud "D:/qt/PlaneWar/res/bg.wav" //D:\qt\PlaneWar\res\bg.wav中斜杠反向
#define Sound_bomb "D:/qt/PlaneWar/res/bomb.wav"
#endif // CONFIG_H
mainscene.cpp:
#include "mainscene.h"
#include<ctime>
#include<QSound>
#include<QApplication>
mainScene::mainScene(QWidget *parent)
: QWidget(parent)
{
InitScene();//初始化
playGame();//开始
// DickMenu *dick;
// dick=new DickMenu;
thread=new MyThread();
connect(thread,&MyThread::isDone,[=]()
{
this->close();
});
}
mainScene::~mainScene()
{
}
void mainScene::InitScene()
{
//设置窗口固定
setFixedSize(GAME_Width,GAME_Heigth);
//设置标题
setWindowTitle(GAME_Title);
//设置窗口图标
setWindowIcon(QIcon(GAME_ICON));
//定时器
m_timer.setInterval(GAME_Rate);
enemy_recorder=0;//敌机出场时间间隔记录
//随机数种子
srand((unsigned int)time(NULL));
}
void mainScene::playGame()
{
m_timer.start(); //启动定时器
//背景音乐
QSound::play("D:/qt/PlaneWar/res/bg.wav");
//监听定时器发出信号
connect(&m_timer,&QTimer::timeout,[=](){
//敌机出场
enemyToscreen();
//更新坐标
updatePosition();
//刷新绘制到屏幕中)
update();
//碰撞检测
collisionDetection();
});
// connect(this,&mainScene::stoptime,this,&mainScene::Done);
}
void mainScene::updatePosition()
{
//更新地图坐标
M_map.mapPosition();
//发射子弹
hero_plane.shoot();
//计算所有非空闲子弹坐标
for(int i=0;i<bullet_num;i++)
{
//如果非空闲 计算发射位置
if(hero_plane.m_bullets[i].bullet_free==false)
{
hero_plane.m_bullets[i].updateBulletPosition();
}
}
//敌机
for(int i=0;i<ENEMY_NUM;i++)
{
if(m_enemies[i].enemy_free==false)
{
m_enemies[i].updateEnemyPosition();
}
}
//计算爆炸的播放图片
for(int i=0;i<Bomb_NUM;i++)
{
if(m_bombs[i].Bomb_free==false)
{
m_bombs[i].updateInfo();
}
}
}
void mainScene::paintEvent(QPaintEvent *)
{
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);
//绘制飞机
if(hero_plane.hero_free==false)
{
painter.drawPixmap(hero_plane.plane_x,hero_plane.plane_y,hero_plane.m_Plane);
}
//绘制子弹
if(StartPaintBullet==true)
{
for(int i=0;i<bullet_num;i++)
{
//如果非空闲 绘制
if(hero_plane.m_bullets[i].bullet_free==false)
{
painter.drawPixmap(hero_plane.m_bullets[i].bullet_x,hero_plane.m_bullets[i].bullet_y,
hero_plane.m_bullets[i].m_bullet);
}
}
}
//绘制敌机
for(int i=0;i<ENEMY_NUM;i++)
{
//如果非空闲 绘制
if(m_enemies[i].enemy_free==false)
{
painter.drawPixmap(m_enemies[i].enemy_x,
m_enemies[i].enemy_y,
m_enemies[i].m_enemy);
}
}
//绘制爆炸
for(int i=0;i<Bomb_NUM;i++)
{
if(m_bombs[i].Bomb_free==false)
{
painter.drawPixmap(m_bombs[i].Bomb_x,m_bombs[i].Bomb_y,
m_bombs[i].m_pixArr[m_bombs[i].bombing_index]);
}
}
}
void mainScene::mouseMoveEvent(QMouseEvent *event) //鼠标拖拽 飞机随之移动
{
int x=event->x()-hero_plane.plane_rect.width()*0.5;
int y=event->y()-hero_plane.plane_rect.height()*0.5;
//边界检测
if(x<=0)
{
x=0;
}
if(x>GAME_Width-hero_plane.plane_rect.width())
{
x=GAME_Width-hero_plane.plane_rect.width();
}
if(y<=0)
{
y=0;
}
if(y>=GAME_Heigth-hero_plane.plane_rect.height())
{
y=GAME_Heigth-hero_plane.plane_rect.height();
}
hero_plane.setPlanePosition(x,y);
}
void mainScene::enemyToscreen() //敌机出场
{
enemy_recorder++;
if(enemy_recorder<ENEMY_INTERVAL)
{
return;
}
enemy_recorder=0;
for(int i=0;i<ENEMY_NUM;i++)
{
if(m_enemies[i].enemy_free)
{
m_enemies[i].enemy_free=false;
//坐标
m_enemies[i].enemy_x=rand()%(GAME_Width-m_enemies[i].enemy_rect.width());
m_enemies[i].enemy_y=-m_enemies[i].enemy_rect.height();
break;
}
}
}
void mainScene::collisionDetection()
{
//遍历所有非空闲的敌机
for(int i=0;i<ENEMY_NUM;i++)
{
if(m_enemies[i].enemy_free)
{
continue;//空闲飞机 跳转到下一次循环
}
if(hero_plane.plane_rect.intersects(m_enemies[i].enemy_rect))//本方飞机爆炸
{
hero_plane.hero_free=true;
StartPaintBullet=false; //不绘制子弹
StartCheckEnemy=false; //不检测子弹与敌机碰撞
hero_plane.plane_rect.setHeight(0);
hero_plane.plane_rect.setWidth(0);
for(int k=0;k<Bomb_NUM;k++)
{
if(m_bombs[k].Bomb_free)
{
//QSound::play(Sound_bomb); //爆炸音效
//空闲的爆炸 可以播放爆炸了
m_bombs[k].Bomb_free=false;
//更新爆炸坐标
m_bombs[k].Bomb_x=hero_plane.plane_x;
m_bombs[k].Bomb_y=hero_plane.plane_y;
//emit stoptime();
break;
}
}
thread->start();
}
if(StartCheckEnemy==true)
{
for(int j=0;j<bullet_num;j++) //遍历子弹
{
if(hero_plane.m_bullets[j].bullet_free)
{
continue;
}
//如果子弹框和敌机框相交
if(m_enemies[i].enemy_rect.intersects(hero_plane.m_bullets[j].bullet_rect))
{
m_enemies[i].enemy_free=true;
hero_plane.m_bullets[j].bullet_free=true;
//爆炸效果播放
for(int k=0;k<Bomb_NUM;k++)
{
if(m_bombs[k].Bomb_free)
{
//QSound::play(Sound_bomb); //爆炸音效
//空闲的爆炸 可以播放爆炸了
m_bombs[k].Bomb_free=false;
//更新爆炸坐标
m_bombs[k].Bomb_x=m_enemies[i].enemy_x;
m_bombs[k].Bomb_y=m_enemies[i].enemy_y;
break;
}
}
}
}
}
}
}
//void mainScene::Done()
//{
// QMessageBox::information(this,"defeat","游戏失败");
// exit(0);
//}
//void mainScene::keyPressEvent(QKeyEvent *event)
//{
// setFocusPolicy(Qt::StrongFocus);
// installEventFilter(this);
// if(event->type()==QEvent::KeyPress)
// {
// QKeyEvent *keyEvent=static_cast<QKeyEvent*>(event);
// if(keyEvent->key()==Qt::Key_Space)
// {
// qDebug()<<1;
// this->m_mutex.lock();
// return;
// }
// if(keyEvent->key()==Qt::Key_0)
// {
// qDebug()<<0;
// this->m_mutex.unlock();
// return;
// }
// }
//}
heroplane.cpp:
#include "heroplane.h"
#include"config.h"
#include"map.h"
HeroPlane::HeroPlane()
{
m_Plane.load(Plane_Model);//设置飞机模型
//初始化飞机坐标
plane_x=(GAME_Width-m_Plane.width())*0.5;
plane_y=GAME_Heigth-m_Plane.height();
//初始化矩形边框
plane_rect.setWidth(m_Plane.width());
plane_rect.setHeight(m_Plane.height());
plane_rect.moveTo(plane_x,plane_y);
hero_free=false;
m_recorder=0;
}
void HeroPlane::shoot()
{
//累加时间间隔记录变量
m_recorder++;
//如果记录的数字未达到子弹发射的间隔
if(m_recorder<bullet_interval)
{
return;//不发射
}
m_recorder=0;
//发射子弹
for(int i=0;i<bullet_num;i++)
{
//如果子弹空闲 则发射
if(m_bullets[i].bullet_free)
{
//将空闲状态改为假
m_bullets[i].bullet_free=false;
//设置子弹坐标
m_bullets[i].bullet_x=plane_x+plane_rect.width()*0.5-10;
m_bullets[i].bullet_y=plane_y-25;
break;
}
}
}
void HeroPlane::setPlanePosition(int x, int y)
{
plane_x=x;
plane_y=y;
plane_rect.moveTo(plane_x,plane_y);
}
enemyplane.cpp:
#include "enemyplane.h"
#include"startgame.h"
#include<QDebug>
EnemyPlane::EnemyPlane()
{
StartGame *str;
str=new StartGame();
m_enemy.load(str->EnemyPlaneStyle);
//m_enemy.load(enemyplane_model);
//敌机位置
enemy_x=0;
enemy_y=0;
//敌机状态
enemy_free=true;
//敌机速度
enemy_speed=ENEMY_SPEED;
//敌机矩形
enemy_rect.setWidth(m_enemy.width());
enemy_rect.setHeight(m_enemy.height());
enemy_rect.moveTo(enemy_x,enemy_y);
}
void EnemyPlane::updateEnemyPosition()
{
//空闲敌机 不计算坐标
if(enemy_free)
{
return;
}
enemy_y+=enemy_speed;
enemy_rect.moveTo(enemy_x,enemy_y);
//如果超出屏幕
if(enemy_y>GAME_Heigth)
{
enemy_free=true;
}
}
startgame.cpp:
#include "startgame.h"
#include "ui_startgame.h"
#include"QDebug"
static int Map=1; //静态全局变量 程序退出前一直保持最新值
StartGame::StartGame(QWidget *parent) :
QDialog(parent),
ui(new Ui::StartGame)
{
ui->setupUi(this);
this->setWindowTitle("飞机大战");
//ui->pushButtonStart->setStyleSheet("font-size:15px;color:rgb(0,255,0,255)");
ui->stackedWidget->setCurrentWidget(ui->pageStart);
ui->spinBox->setMaximum(5);
ui->spinBox->setValue(5);
// mainScene *m;
// //m=new mainScene();
// connect(m,&mainScene::ReturnMenu,[=]()
// {
// this->show();
// m->close();
// });
}
StartGame::~StartGame()
{
delete ui;
}
void StartGame::on_pushButtonStart_clicked()
{
this->close();
mainScene *m;
m=new mainScene();
m->show();
}
// 下列方法会导致窗口一闪而过mainScene创建在stack上,生命期是大括号内
// mainScene *m;
// m=new mainScene();
// mainScene 通过new创建在heap上, 在程序退出时才会被析构
// this->hide();
// mainScene m;
// m->show();
void StartGame::on_pushButtonStart_Design_clicked()
{
ui->stackedWidget->setCurrentWidget(ui->page_2);
}
void StartGame::on_pushButtonStart_Exit_clicked()
{
exit(0);
}
void StartGame::on_pushButtonSureDeSign_clicked()
{
ui->stackedWidget->setCurrentWidget(ui->pageStart);
Map=ui->spinBox->text().toInt(); //Map的值为spinBox的当前值并保持不变直到下次在此页面修改spinBox的值并确定
//MapStyle=QString(":/new/prefix1/res/img_bg_level_%1.jpg").arg(Map);
}
void StartGame::changeMap()
{
MapStyle=QString(":/new/prefix1/res/img_bg_level_%1.jpg").arg(Map);
}
bomb.cpp:
#include "bomb.h"
#include<QDebug>
Bomb::Bomb()
{
//将所有爆炸pixmap放入数组中
for(int i=1;i<=Bomb_max;i++)
{
QString str=QString(Bomb_model).arg(i);
m_pixArr.push_back(QPixmap(str));
}
//坐标
Bomb_x=0;
Bomb_y=0;
Bomb_free=true;
bombing_index=0;
Bomb_recorder=0;
}
void Bomb::updateInfo()
{
//空闲状态下的爆炸效果直接return
if(Bomb_free)
{
return;
}
Bomb_recorder++;
if(Bomb_recorder<Bomb_Interval)
{
return;
}
Bomb_recorder=0;
bombing_index++;//切换爆炸显示图片下标
if(bombing_index>Bomb_max-1)//数组下标从0开始计算
{
bombing_index=0;
Bomb_free=true;
}
}
bullet.cpp:
#include "bullet.h"
#include<QDebug>
bullet::bullet()
{
//加载资源
m_bullet.load(bullet_model);
//子弹坐标
bullet_x=(GAME_Width-m_bullet.width())*0.5;
bullet_y=GAME_Heigth;
//子弹状态
bullet_free=true;
//子弹速度
bullet_speed=BULLET_SPEED;
//子弹矩形边框
bullet_rect.setWidth(m_bullet.width());
bullet_rect.setHeight(m_bullet.height());
bullet_rect.moveTo(bullet_x,bullet_y);
}
void bullet::updateBulletPosition()
{
//空闲状态下的子弹无需计算坐标
if(bullet_free)
{
return;
}
bullet_y-=bullet_speed;//子弹向上移动
bullet_rect.moveTo(bullet_x,bullet_y);
if(bullet_y<=0)//子弹位置超出屏幕状态为为空闲
{
bullet_free=true;
}
}
dickmenu.cpp:
#include "dickmenu.h"
#include "ui_dickmenu.h"
#include<QDebug>
DickMenu::DickMenu(QWidget *parent) :
QDialog(parent),
ui(new Ui::DickMenu)
{
ui->setupUi(this);
this->setWindowTitle("游戏失败");
}
DickMenu::~DickMenu()
{
delete ui;
}
void DickMenu::on_pushButton_clicked()
{
StartGame *st;
st=new StartGame();
st->show();
this->close();
emit returnWindow();
}
void DickMenu::on_pushButton_2_clicked()
{
exit(0);
}
map.cpp:
#include "map.h"
#include"config.h"
#include"startgame.h"
#include<QDebug>
map::map()
{
//初始化加载地图对象
StartGame *str;
str=new StartGame();
str->changeMap();
m_map1.load(str->MapStyle);
m_map2.load(str->MapStyle);
// m_map1.load(Map_Path);
// m_map2.load(Map_Path);
//初始化Y轴坐标
m_map1_posY=-GAME_Heigth;
m_map2_posY=0;
//地图滚动速度
m_scroll_speed=Map_Scroll_Speed;
}
void map::mapPosition()
{
//处理第一张图片滚动位置
m_map1_posY+=m_scroll_speed;
if(m_map1_posY>=0)
{
m_map1_posY=-GAME_Heigth;
}
//处理第二张图片滚动位置
m_map2_posY+=m_scroll_speed;
if(m_map2_posY>=GAME_Heigth)
{
m_map2_posY=0;
}
}
mythread.cpp:
#include "mythread.h"
#include"QMessageBox"
#include"dickmenu.h"
MyThread::MyThread(QObject *parent) : QThread(parent)
{
connect(this,&MyThread::isDone,this,&MyThread::dicked);
}
void MyThread::run()
{
sleep(2);
emit isDone();
}
void MyThread::dicked()
{
DickMenu *dick;
dick=new DickMenu;
dick->show();
}
main.cpp:
#include "mainscene.h"
#include <QApplication>
#include"startgame.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
StartGame st;
st.show();
return a.exec();
}
上一篇: 图的深度优先搜索和广度优先搜索
下一篇: matplotlib 3D图