飞道的博客

树莓派c++实验八:飞机大战小游戏制作实验

431人阅读  评论(0)

一、实验目的
1.了解 qt 图形开发基本原理
2.掌握 C++的整体架构
3.深入理解 C++对象的机制和实现方法

二、实验原理
本实验以树莓派作为控制器,以 qt crearor 作为开发工具,完成一个飞机大战的小游戏。

三、使用仪器、材料
1.树莓派开发板
2. qt crearor

四、实验步骤
(1)实现玩家类的创建并能控制其移动
(2)实现敌机类的创建及其自动移动
(3)实现敌机和玩家的碰撞检测
(4)实现子弹类的创建及子弹和敌机、子弹和玩家的碰撞检测
(5)实现敌机的随机创建和销毁
(6)实现子弹的创建和销毁
(7)添加文字和背景图片,完成基本的界面美化

五、实验过程原始记录(计算机源代码)

#ifndef BULLET_H
#define BULLET_H//子弹类
#include "config.h"//导入配置文件
#include <QPixmap>
class bullet
{
   
public:
    bullet();
    QPixmap m_bullet;
    QRect rect;
    int x;//坐标
    int y;
    int speed;//速度
    bool free;
    void setPosistion();//设置位置
};

#endif // BULLET_H
#ifndef CONFIG_H
#define CONFIG_H//配置类
enum Direction//定义方向上下左右
{
   
    DOWN,
    UP,
    LEFT,
    RIGHT
};
//定义一些基本参数
#define ENEMYBULLET_INTERVAL 5
#define ENEMY_APPEAR 50
#define ENEMY_NUM 15
#define ENMEY_INTERVAL 30
#define BUL_NUM 30
#define BUL_SPEED 5
#define MAP_SPEED 2
#define GAME_RATE 10
#define ENEMY_SPEED 5
#define BULLET_NUM 5
#define BUL_INTERVAL 20
#define GAME_WIDTH 480
#define PLANE_SPEED 10
#define GAME_HEIGTH 650
#define BULLET_SPEED 5
#define ONCE_FINALHIT 5
#define FINALHIT_NUM  10
#define TOTAL_FINALHIT 50
#define FINALHIT_SPEED 10
//定义飞机大战中所用的图片
#define GAME_TITLE "飞机大战"
#define MAP_PATH ":/res/map.jpg"
#define GAME_ICO ":/res/game.ico"
#define BULLET_PATH ":/res/bullet.png"
#define ENEMY_PATH  ":/res/1.png"
#define HEROPLANE_PATH ":/res/heroplane.png"
#define PLANEDEATH_PATH ":/res/plane_death.png"
#define ENEMYDEATH_PATH ":/res/enemy_death.png"
#define ENEMYBULLET_PATH ":/res/enemy_bullet.png"

#endif // CONFIG_H
#ifndef ENEMY_H
#define ENEMY_H//敌机类
#include "config.h"
#include <QPixmap>
#include "enemybullet.h"
class Enemy
{
   
public:
    Enemy();
    QPixmap pic;
    QRect rect;
    EnemyBullet bul[BUL_NUM];//定义敌机子弹数组,
    QPixmap pic_death;
    int x;//定义坐标
    int y;
    int speed;// 速度
    bool free;
    bool death;//是否死亡
    int recorder;//再次还原
    void shoot();//射击函数
    void explode();
    void updatePosistion();//更新位置
    void allDeath();//敌机死亡
};

#endif // ENEMY_H
#ifndef ENEMYBULLET_H
#define ENEMYBULLET_H//敌机子弹类
#include <QPixmap>
#include "bullet.h"
class EnemyBullet : public bullet//继承子弹类
{
   
public:
    EnemyBullet();
    void setPosistion();//设置子弹位置,
    void allDisappear();//子弹消失
};

#endif // ENEMYBULLET_H
#ifndef FINALHIT_H//大招类
#define FINALHIT_H
#include "finalhit.h"
#include <QPixmap>
#include "config.h"
class FinalHit
{
   
public:
    FinalHit();
    QPixmap finalHit;
    QRect rect;
    int x;//定义坐标
    int y;
    int speed;//速度
    bool free;
    void updatePosistion();//更新位置
};

#endif
#ifndef HEROPLANE_H
#define HEROPLANE_H//本机类
#include "config.h"
#include <QPixmap>
#include <QKeyEvent>
#include "bullet.h"
#include "finalhit.h"
class HeroPlane
{
   
public:
    HeroPlane();

    QPixmap plane;
    QPixmap plane_death;
    QRect rect;
    QRect death_rect;
    int x;//定义坐标
    int y;
    int life;//生命值
    bool death;//生命值
    int finahit_num;//大招数量
    void shoot();//射击函数
    void final_hit();//大招函数
    bullet m_bullet[BULLET_NUM];//子弹数组
    FinalHit m_finalhit[TOTAL_FINALHIT];//大招数组
};

#endif // HEROPLANE_H
#ifndef MAINSCENE_H
#define MAINSCENE_H//基础控制类:
#include <QMainWindow>
#include <QTimer>
#include "map.h"//地图类
#include "heroplane.h"//本机类
#include <QKeyEvent>
#include "bullet.h"//子弹类
#include "enemy.h"//敌机类
#include <QProgressBar>
namespace Ui {
   
class MainScene;
}
class MainScene : public QMainWindow
{
   
    Q_OBJECT
public:
    explicit MainScene(QWidget *parent = 0);
    ~MainScene();
    QTimer enemy_timer;//定义敌机定时器,用于增加敌机数量、显示爆炸
    QTimer timer;//本机定时器,用于移动飞机、判断战机和敌机、敌机和子弹是否发生碰撞
    Map map;//地图
    HeroPlane plane;//地图
    bullet m_bullet[BULLET_NUM];//子弹数组
    Enemy enemy[ENEMY_NUM];//敌机数组
Enemy m;
    int enemy_recorder;//定义敌机的恢复数量
    void Init_Scene();//初始化屏幕函数
    void keyPressEvent(QKeyEvent *event);//键盘点击事件
    void mouseMoveEvent(QMouseEvent *event);//鼠标点击事件
    void crash();//敌机碰撞
public slots://定义slots创建用于接收的槽函数
    void play_game();//开始游戏
    void updatePosistion();//更新本机位置更新本机位置
    void paintEvent(QPaintEvent *event);
    void enemy_updatePosistion();//更新敌机位置
private:
    Ui::MainScene *ui;
};

#endif // MAINSCENE_H
#ifndef MAP_H
#define MAP_H//背景图类
#include <QPixmap>
class Map
{
   
public:
    Map();
    QPixmap map1;//定义两张背景图
    QPixmap map2;
    int map1_y;//定义两张背景图的移动位置
    int map2_y;
    int speed;//背景图的移动速度
    void updataPosistion();//更新背景图位置
};
#endif // MAP_H
#include "map.h"
#include "config.h"
Map::Map()
{
   
    map1.load(MAP_PATH);//采用两张图片
    map2.load(MAP_PATH);
    map1_y = 0;//初始化图片位置一张在桌面水平线上,一张在桌面水平线下
    map2_y = -GAME_HEIGTH;
}

void Map::updataPosistion()//更新背景图位置
{
   
    map1_y += MAP_SPEED;//一张图片不断往下移动,另一张不断从上补充
    if(map1_y >= GAME_HEIGTH)
    {
   
        map1_y = 0;
    }
    map2_y += MAP_SPEED;
    if(map2_y >= 0)
    {
   
        map2_y = -GAME_HEIGTH;
    }
}
#include "mainscene.h"
#include "ui_mainscene.h"
#include "config.h"
#include <QPainter>
#include <QDebug>
#include <ctime>
#include <QProgressBar>
#include <QPixmap>
MainScene::MainScene(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainScene)
{
   
    ui->setupUi(this);
    enemy_recorder = 10;//初始化敌机数量10个,
    Init_Scene();
    m.pic.load(":/res/1.png");//初始化屏幕,设置碰撞的结果图片,设置碰撞结果图的长度和宽度
    m.rect.setWidth(m.pic.width());
    m.rect.setHeight(m.pic.height());
    m.rect.moveTo(0, 0);
}
MainScene::~MainScene()
{
   
    delete ui;
}
void MainScene::Init_Scene()//初始化屏幕的函数
{
   
    setFixedSize(GAME_WIDTH, GAME_HEIGTH);//设置字体大小,窗口标题,窗口图标
    setWindowTitle(GAME_TITLE);
    setWindowIcon(QIcon(GAME_ICO));
    ui->liftProcess->setOrientation(Qt::Vertical);
    ui->liftProcess->setRange(0, 20);
    ui->liftProcess->setValue(20);
    ui->liftProcess->setFixedSize(10, 250);
    ui->liftProcess->move(460, 0);
    ui->liftProcess->setTextVisible(false);
    connect(&timer, &QTimer::timeout, [=]()//连接本机的定时器更新本机位置
    {
   
        updatePosistion();
        update();
        crash();
    });
    timer.start(GAME_RATE);//启动定时器
    connect(&enemy_timer, &QTimer::timeout, [=]()//连接敌机的定时器更新敌机位置
    {
   
        enemy_updatePosistion();
    });
    enemy_timer.start(ENEMY_APPEAR);//启动敌机定时器
    qsrand(time(NULL));
}

void MainScene::play_game()//启动游戏的函数
{
   
    connect(&timer, &QTimer::timeout, [=]()//连接定时器更新位置
    {
   
        updatePosistion();
    });
    timer.start(GAME_RATE);//启动定时器
}

void MainScene::updatePosistion()//更新位置的函数
{
   
    map.updataPosistion();//先更新背景图的位置
    for(int i=0; i<BULLET_NUM; i++)//更新子弹的位置
    {
   
        if(!plane.m_bullet[i].free)
        {
   
            plane.m_bullet[i].setPosistion();
        }
    }
    for(int i=0; i<TOTAL_FINALHIT; i++)//更新本机大招的位置
    {
   
        if(!plane.m_finalhit[i].free)
        {
   
            plane.m_finalhit[i].updatePosistion();
        }
    }
    for(int i=0; i<ENEMY_NUM; i++)//更新敌机子弹的位置
    {
   
        for(int j=0; j<BULLET_NUM; j++)
        {
   
            if(!enemy[i].bul[j].free)
            {
   
                enemy[i].bul[j].setPosistion();
            }
        }
    }
}
void MainScene::paintEvent(QPaintEvent *event){
   //重绘事件
    static int count = 0;
    QPainter painters(this);
    //绘制动态背景
    painters.drawPixmap(0, 0, m.pic);
    painters.drawPixmap(0, map.map1_y, map.map1);
    painters.drawPixmap(0, map.map2_y, map.map2);
    //绘制我方飞机活着和死亡的状态
    if(plane.death){
   
        painters.drawPixmap(plane.x, plane.y, plane.plane_death);
        enemy_timer.stop();
        timer.stop();
    }else{
   
        painters.drawPixmap(plane.x, plane.y, plane.plane);
    }
    //绘制我方子弹
    for(int i=0; i<BULLET_NUM; i++){
   
        if(!plane.m_bullet[i].free){
   
            painters.drawPixmap(plane.m_bullet[i].x, plane.m_bullet[i].y, plane.m_bullet[i].m_bullet);
        }
    }
    //绘制我方大招
    for(int i=0; i<TOTAL_FINALHIT; i++){
   
        if(!plane.m_finalhit[i].free){
   
            painters.drawPixmap(plane.m_finalhit[i].x, plane.m_finalhit[i].y, plane.m_finalhit[i].finalHit);
        }
    }
    //绘制敌方飞机活着和死亡的状态,绘制敌方子弹
    for(int i=0; i<ENEMY_NUM; i++){
   
        if(!enemy[i].free){
   
            painters.drawPixmap(enemy[i].x, enemy[i].y, enemy[i].pic);
        }
        for(int j=0; j<BULLET_NUM; j++){
   
            if(!enemy[i].bul[j].free){
   
                painters.drawPixmap(enemy[i].bul[j].x, enemy[i].bul[j].y, enemy[i].bul[j].m_bullet);
            }
        }
        if(enemy[i].death){
   
            count++;
            if(count >= 10){
   
                count = 0;
                 enemy[i].death = false;
            }
            painters.drawPixmap(enemy[i].x, enemy[i].y, enemy[i].pic_death);
        }
    }
}
void MainScene::mouseMoveEvent(QMouseEvent *event){
   // 鼠标点击事件的函数
    if(event->x()>=plane.x && event->x()<=(plane.x+60) && event->y()>=plane.y && event->y()<=plane.y+85){
   
        plane.x = event->x() - plane.rect.width() *0.5;     //鼠标位置 - 飞机矩形的一半
        plane.y = event->y() - plane.rect.height()*0.5;
        //进行边界检测
        if(plane.x <= 0 ){
   
            plane.x = 0;
        }
        if(plane.x >= GAME_WIDTH - plane.rect.width()){
   
            plane.x = GAME_WIDTH - plane.rect.width();
        }
        if(plane.y <= 0){
   
            plane.y = 0;
        }
        if(plane.y >= GAME_HEIGTH - plane.rect.height()){
   
            plane.y = GAME_HEIGTH - plane.rect.height();
        }
        qDebug() << "x = " << plane.x << "y = " << plane.y;
        plane.rect.moveTo(plane.x, plane.y);
    }
}
void MainScene::keyPressEvent(QKeyEvent *event){
   //键盘点击事件的函数
    if(event->key() == Qt::Key_W)   //up,键盘上点击W、S、A、D分别对应我方飞机上、下、左、右移动功能
    {
   
        if(plane.y >= plane.rect.width()){
   
            plane.y -= PLANE_SPEED;
        }
    }
    else if(event->key() == Qt::Key_S)  //down
    {
   
        if(plane.y <= (GAME_HEIGTH-plane.rect.height())){
   
            plane.y += PLANE_SPEED;
        }
    }
    else if(event->key() == Qt::Key_A)  //left
    {
   
        if(plane.x >= 0){
   
            plane.x -= PLANE_SPEED;
        }
    }
    else if(event->key() == Qt::Key_D){
   //right
        if(plane.x <= GAME_WIDTH-plane.rect.width()){
   
            plane.x += PLANE_SPEED;
        }
    }
    else if(event->key() == Qt::Key_J){
   //键盘上点击J发射子弹
        plane.shoot();
    }
    else if(event->key() == Qt::Key_K){
   //键盘上点击K发射大招
        if(plane.finahit_num > 0){
   
            plane.finahit_num--;
            plane.final_hit();
            for(int i=0; i<ENEMY_NUM; i++){
   
                if(!enemy[i].free){
   
                    enemy[i].allDeath();
                }
                for(int j=0; j<BULLET_NUM; j++){
   
                    enemy[i].bul[j].allDisappear();
                }
            }
        }
    }
    plane.rect.moveTo(plane.x, plane.y);
}
void MainScene::enemy_updatePosistion(){
   //更新敌方飞机位置的函数,
    for(int j=0; j<ENEMY_NUM; j++){
   //如果我方飞机放了大招,敌机清零,
        if(enemy[j].recorder > ENEMYBULLET_INTERVAL && (!enemy[j].free)){
   
            enemy[j].recorder = 0;
            enemy[j].shoot();
        }
        if(!enemy[j].free){
   //如果敌机为空,那么增加敌机数量并且更新敌机位置
            enemy[j].recorder++;
            enemy[j].updatePosistion();
        }
    }
    enemy_recorder++;
    if(enemy_recorder >= 10){
   
        enemy_recorder = 0;
        for(int i=0; i<ENEMY_NUM; i++){
   
            if(enemy[i].free){
   
                enemy[i].free = false;                
                enemy[i].x = qrand() % (GAME_WIDTH-enemy[i].rect.width());
                enemy[i].y = 0;
                enemy[i].speed = (qrand()%2) ? ENEMY_SPEED : -ENEMY_SPEED;
                enemy[i].rect.moveTo(enemy[i].x, enemy[i].y);
                break;
            }
        }
    }
}
void MainScene::crash()//检测碰撞的函数,
{
   
    for(int j=0; j<BULLET_NUM; j++){
   //第一部分检测我方飞机子弹和敌机相撞的爆炸
        if(!plane.m_bullet[j].free){
   //遍历我方飞机子弹
            for(int i=0; i<ENEMY_NUM; i++){
   
                if(!enemy[i].free){
   //如果检测到与敌方飞机相撞,让这架敌机消失free,并标记其死亡
                    if(enemy[i].rect.intersects(plane.m_bullet[j].rect)){
   
                        enemy[i].free = true;
                        plane.m_bullet[j].free = true;
                        enemy[i].death = true;
                        break;
                    }
                }
            }
        }
    }
    for(int j=0; j<ENEMY_NUM; j++) {
   //第二部分检测我方飞机和敌机相撞的爆炸
        if(!enemy[j].free) {
   //遍历敌方飞机
            if(enemy[j].rect.intersects(plane.rect)){
   //如果检测到与敌方飞机相撞,让这架敌机消失free,并标记其死亡,同时我方飞机的生命值减2
                enemy[j].free = true;
                enemy[j].death = true;
                plane.life -= 2;
                ui->liftProcess->setValue(plane.life);
                if(plane.life <= 5 && plane.life > 0){
   
                    ui->liftProcess->setStyleSheet("QProgressBar::chunk { background-color: rgb(255, 0, 0) }");
                }
                else if(plane.life <= 0){
   
                    ui->liftProcess->setValue(0);
                    plane.death = true;
                }
            }
        }
    }
    for(int j=0; j<ENEMY_NUM; j++) {
   //第三部分检测我方飞机和敌机子弹相撞的爆炸
        for(int i=0; i<BULLET_NUM; i++){
   //遍历敌方飞机和敌方子弹
            if((!enemy[j].free) && (!enemy[j].bul[i].free)){
   
                if(plane.rect.intersects(enemy[j].bul[i].rect)){
   //如果检测到与敌方飞机的子弹相撞,只让我方飞机的生命值减1,敌方飞机保持不变
                    enemy[j].bul[i].free = true;
                    plane.life--;
                    ui->liftProcess->setValue(plane.life);
                    if(plane.life <= 5 && plane.life > 0){
   
                        ui->liftProcess->setStyleSheet("QProgressBar::chunk { background-color: rgb(255, 0, 0) }");
                    }
                    else if(plane.life <= 0){
   
                        plane.death = true;
                    }
                }
            }
        }
    }

}

实验结果


转载:https://blog.csdn.net/lf18879954995/article/details/115936011
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场