在学习完QT后,我尝试做了一下飞机大战这个小游戏。

首先是小游戏需要实现的功能:

1.滚动的背景

2.子弹的制作和射击

3.敌人的制作

4.爆炸效果

首先我们创建好项目后,我们开始创建新的头文件,用来配置所有的数据。这需要我们先把飞机大战需要的png图片素材先整理好,代码如下:

/**********  游戏配置数据 **********/
#define GAME_WIDTH  512  //宽度
#define GAME_HEIGHT 768  //高度
#define GAME_TITLE "飞机大战 sjn" //标题
#define GAME_RES_PATH":/resnew/app.ico"
#define GAME_ICON ":/res/app.ico"  //图标路径
#define GAME_RATE  10  //单位毫秒

/**********  地图配置数据 **********/
#define MAP_PATH  ":/resnew/img_bg_level_5.jpg" //地图图片路径
#define MAP_SCROLL_SPEED 2  //地图滚动速度

/**********  飞机配置数据 **********/
#define HERO_PATH ":/resnew/app.ico"

/**********  子弹配置数据 **********/
#define BULLET_PATH ":/resnew/bullet_1.png"   //子弹图片路径
#define BULLET_SPEED 5  //子弹移动速度

#define BULLET_NUM 30   //弹匣中子弹总数
#define BULLET_INTERVAL 20 //发射子弹时间间隔

/**********  敌机配置数据 **********/
#define ENEMY_PATH  ":/resnew/img-plane_1.png"  //敌机资源图片
#define ENEMY_SPEED 5  //敌机移动速度
#define ENEMY_NUM   20  //敌机总数量
#define ENEMY_INTERVAL  30  //敌机出场时间间隔

/**********  爆炸配置数据 **********/
#define BOMB_PATH  ":/resnew/bomb-1.png"   //爆炸资源图片
#define BOMB_NUM  20     //爆炸数量
#define BOMB_MAX  7      //爆炸图片最大索引
#define BOMB_INTERVAL 20   //爆炸切图时间间隔

#define SOUND_BACKGROUND ":/res/bg.wav"
#define SOUND_BOMB ":/res/bomb.wav"

#endif // CONFIG_H

然后我们要开始写地图功能的编写

为了实现地图的滚动,也就是需要循环,这时可以调用游戏运行定时器,启动定时器,监听定时器信号实现游戏循环,看起来就是地图的滚动,代码如下

map.h

#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

map.cpp:

#include "map.h"
#include "config.h"

Map::Map()
{
    //初始化加载地图对象
    m_map1.load(MAP_PATH);
    m_map2.load(MAP_PATH);

    //设置坐标
    m_map1_posY = -GAME_HEIGHT;
    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_HEIGHT;
    }

    //处理第二张图片滚动
    m_map2_posY += m_scroll_speed;
    if(m_map2_posY >= GAME_HEIGHT)
    {
        m_map2_posY = 0;
    }

}

启动定时器的代码如下:

1.在MainScene.h中添加新的成员函数以及成员对象

//启动游戏  用于启动定时器对象
    void playGame();
    //更新坐标
    void updatePosition();
    //绘图事件
    void paintEvent(QPaintEvent *event);

在MainScene.cpp中实现成员函数,代码如下:

// 启动定时器
    m_Timer.start();

    //监听定时器的信号
    connect(&m_Timer , &QTimer::timeout,[=](){
        //敌机出场
        enemyToScene();
        //更新游戏中所有元素的坐标
        updatePosition();
        //游戏中的元素 绘制到屏幕中
        update(); //再调用paintEvent函数

做好了这些,飞机大战游戏的大框架已经构建好了,之后我们来添加自己想要的素材和功能,

首先是我们自己操控的飞机,,步骤如下:

1.创建文件和类

2.添加成员函数和成员属性

3.实现成员函数

4.创建飞机对象并显示

5.可以拖拽

当我们创建好文件和类后,需要添加属性代码:

 //发射子弹
    void shoot();
    //设置飞机位置
    void setPosition(int x, int y);

public:
    //飞机资源 对象
    QPixmap m_Plane;

    //飞机坐标
    int m_X;
    int m_Y;

    //飞机的矩形边框
    QRect m_Rect;

成员函数实现

因为上边config.h中,我展示的是所有代码,所以就不展示此处的飞机配置参数设置的代码了,

所以在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() - 100;

    //矩形边框 碰撞检测用
    m_Rect.setWidth(m_Plane.width());
    m_Rect.setHeight(m_Plane.height());
    m_Rect.moveTo(m_X,m_Y);

    //初始化间隔记录变量
    m_recorder = 0;
}

void HeroPlane::setPosition(int x, int y)
{
    m_X = x;
    m_Y = y;
    m_Rect.moveTo(m_X,m_Y);
}

加入素材,在MainScene.h中添加代码如下:

//创建飞机对象
    HeroPlane m_hero;

MainScene.cpp中:

 //绘制飞机
    painter.drawPixmap(m_hero.m_X,m_hero.m_Y,m_hero.m_Plane);

最后我们编写拖拽飞机的指令

MainScene.h:

void mouseMoveEvent(QMouseEvent *);

MainScene.cpp:

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);
}

然后就是子弹的功能,创建好子弹的文件和类后,我们需要在bullet.h中添加代码如下:

#ifndef BULLET_H
#define BULLET_H
#include "config.h"
#include <QPixmap>

class Bullet
{
public:
    Bullet();

    //更新子弹坐标
    void updatePosition();

public:
    //子弹资源对象
    QPixmap m_Bullet;
    //子弹坐标
    int m_X;
    int m_Y;
    //子弹移动速度
    int m_Speed;
    //子弹是否闲置
    bool m_Free;
    //子弹的矩形边框(用于碰撞检测)
    QRect m_Rect;
};

#endif // BULLET_H

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);
}

void Bullet::updatePosition()
{
    //如果子弹是空闲状态,不需要计算坐标
    if(m_Free)
    {
        return;
    }

    //子弹向上移动
    m_Y -=m_Speed;
    m_Rect.moveTo(m_X,m_Y);

    if(m_Y <= - m_Rect.height())
    {
        m_Free = true;
    }

}

此时子弹的代码已经编写完成,我们需啊使子弹从飞机的位置发射出,这时我们在heroplane.cpp中添加代码:

void HeroPlane::shoot()
{
    //累加事件间隔记录的变量
    m_recorder++;


    //如果记录数字 未达到发射间隔,直接return
    if(m_recorder < BULLET_INTERVAL)
    {
        return;
    }

    m_recorder = 0;

    //发射子弹
    for(int i = 0 ; i < BULLET_NUM;i++)
    {
        //如果是空闲状态的子弹,发射子弹
        if(m_bullets[i].m_Free)
        {
            m_bullets[i].m_Free = false;
            m_bullets[i].m_X = m_X+m_Rect.width()*0.5 - 10;
            m_bullets[i].m_Y = m_Y - 25 ;
            break;
        }

    }
}

当然别忘了,在主场景中也实现添加子弹

MainScene.cpp:

//发射子弹
    m_hero.shoot();

    //计算子弹坐标
    for(int i = 0 ;i < BULLET_NUM;i++)
    {
        //如果子弹状态为非空闲,计算发射位置
        if(m_hero.m_bullets[i].m_Free == false)
        {
            m_hero.m_bullets[i].updatePosition();
        }

    }

然后我们开始敌人飞机的功能实现

首先我们需要创建好文件和类,然后在.h文件中添加成员函数,和成员属性

#ifndef ENEMYPLANE_H
#define ENEMYPLANE_H


#include <QPixmap>

class EnemyPlane
{
public:
    EnemyPlane();

    //更新坐标
    void updatePosition();
public:
    //敌机资源对象
    QPixmap m_enemy;

    //位置
    int m_X;
    int m_Y;

    //敌机的矩形边框(碰撞检测)
    QRect m_Rect;

    //状态
    bool m_Free;

    //速度
    int m_Speed;
};

#endif // ENEMYPLANE_H

然后在.cpp中实现成员函数:

#include "enemyplane.h"
#include "config.h"

EnemyPlane::EnemyPlane()
{
    //敌机资源加载
    m_enemy.load(ENEMY_PATH);

    //敌机位置
    m_X = 0;
    m_Y = 0;

    //敌机状态
    m_Free = true;

    //敌机速度
    m_Speed = ENEMY_SPEED;

    //敌机矩形
    m_Rect.setWidth(m_enemy.width());
    m_Rect.setHeight(m_enemy.height());
    m_Rect.moveTo(m_X,m_Y);
}

void EnemyPlane::updatePosition()
{
    //空闲状态,不计算坐标
    if(m_Free)
    {
        return;
    }

    m_Y += m_Speed;
    m_Rect.moveTo(m_X,m_Y);

    if(m_Y >= GAME_HEIGHT)
    {
        m_Free = true;
    }
}

在MainScene.h中实行敌人飞机的出场

//敌机出场
    void enemyToScene();
    //敌机数组
    EnemyPlane m_enemys[ENEMY_NUM];
    //敌机出场间隔记录
    int m_recorder;
实现成员函数 enemyToScene
void MainScene::enemyToScene()
{
    //累加出场间隔
    m_recorder++;
    if(m_recorder < ENEMY_INTERVAL)
    {
        return;
    }

    m_recorder = 0;

    for(int i = 0 ; i< ENEMY_NUM;i++)
    {
        if(m_enemys[i].m_Free)
        {
            //敌机空闲状态改为false
            m_enemys[i].m_Free = false;
            //设置坐标
            m_enemys[i].m_X = rand() % (GAME_WIDTH - m_enemys[i].m_Rect.width());
            m_enemys[i].m_Y = -m_enemys[i].m_Rect.height();
            break;
        }
    }
}

碰撞效果实现:

void MainScene::collisionDetection()
{
    //遍历所有非空闲的敌机
    for(int i = 0 ;i < ENEMY_NUM;i++)
    {
        if(m_enemys[i].m_Free)
        {
            //空闲飞机 跳转下一次循环
            continue;
        }

        //遍历所有 非空闲的子弹
        for(int j = 0 ; j < BULLET_NUM;j++)
        {
            if(m_hero.m_bullets[j].m_Free)
            {
                //空闲子弹 跳转下一次循环
                continue;
            }

            //如果子弹矩形框和敌机矩形框相交,发生碰撞,同时变为空闲状态即可
            if(m_enemys[i].m_Rect.intersects(m_hero.m_bullets[j].m_Rect))
            {
                //播放音效
                QSound::play(SOUND_BOMB);


                m_enemys[i].m_Free = true;
                m_hero.m_bullets[j].m_Free = true;
最后我们添加爆炸的效果,

bomb.h:

#ifndef BOMB_H
#define BOMB_H

#include "config.h"
#include <QPixmap>
#include <QVector>

class Bomb
{
public:
    Bomb();

    //更新信息(播放图片下标、播放间隔)
    void updateInfo();

public:

    //放爆炸资源数组
    QVector<QPixmap> m_pixArr;

    //爆炸位置
    int m_X;
    int m_Y;

    //爆炸状态
    bool m_Free;

    //爆炸切图的时间间隔
    int m_Recoder;

    //爆炸时加载的图片下标
    int m_index;
};

#endif // BOMB_H

bomb.cpp:

#include "bomb.h"

Bomb::Bomb()
{
    //初始化爆炸图片数组
    for(int i = 1 ;i <= BOMB_MAX ;i++)
    {

        QString str = QString(BOMB_PATH).arg(i);
        m_pixArr.push_back(QPixmap(str));
    }

    //初始化坐标
    m_X = 0;
    m_Y = 0;

    //初始化空闲状态
    m_Free = true;

    //当前播放图片下标
    m_index = 0;

    //爆炸间隔记录
    m_Recoder = 0;
}

void Bomb::updateInfo()
{
    //空闲状态
    if(m_Free)
    {
        return;
    }

    m_Recoder++;
    if(m_Recoder < BOMB_INTERVAL)
    {
        //记录爆炸间隔未到,直接return,不需要切图
        return;
    }
    //重置记录
    m_Recoder = 0;

    //切换爆炸播放图片
    m_index++;
    //注:数组中的下标从0开始,最大是6
    //如果计算的下标大于6,重置为0
    if(m_index > BOMB_MAX-1)
    {
        m_index = 0;
        m_Free = true;
    }
}

MainScene.h中添加爆炸数组:

//爆炸数组
    Bomb m_bombs[BOMB_NUM];
在碰撞检测成员函数中,当发生碰撞时,设置爆炸对象的信息:
for(int k = 0 ; k < BOMB_NUM;k++)
              {
                  if(m_bombs[k].m_Free)
                  {
                      //爆炸状态设置为非空闲
                      m_bombs[k].m_Free = false;
                      //更新坐标
                      m_bombs[k].m_X = m_enemys[i].m_X;
                      m_bombs[k].m_Y = m_enemys[i].m_Y;
                      break;
                  }
              }
在 MainScene.cpp的updatePosition中追加代码:
//计算爆炸播放的图片
    for(int i = 0 ; i < BOMB_NUM;i++)
    {
        if(m_bombs[i].m_Free == false)
        {
           m_bombs[i].updateInfo();
        }
    }
在 MainScene.cpp的paintEvent 中追加绘制爆炸代码:
 //绘制爆炸图片
    for(int i = 0 ; i < BOMB_NUM;i++)
    {
        if(m_bombs[i].m_Free == false)
        {
           painter.drawPixmap(m_bombs[i].m_X,m_bombs[i].m_Y,m_bombs[i].m_pixArr[m_bombs[i].m_index]);
        }
    }

至此,简易的飞机大战小游戏已经完成

最终结果展示:

未能实现功能:

其实还可以有更多的功能实现,比如做一个背景音乐,做一个闯关系统,血量,以及BOSS的挑战,

总结:

学习完QT后,听老师上课讲会发现可以听懂,但自己动手做项目,发现很多知识需要反复去看课堂回放才可以慢慢理解,不懂的知识夜学会了百度来解决问题,很多逻辑性的代码构建需要长时间理解。







												

华清大作业 QT实现飞机大战小游戏相关推荐

  1. Qt学习总结——飞机大战小游戏制作

    Qt学习总结--飞机大战小游戏制作 1. 需求分析 这篇文章写于2020年暑假,完成学校实训项目之后,对自己的项目实践做了一个总结,回顾整个项目的制作过程,同时也复习一下Qt的相关知识,总结项目制作过 ...

  2. C语言—飞机大战小游戏

    哈工大经典C语言大作业-飞机大战小游戏,源码如下,已经通过编译获得评分19+ (满分20)当时还是太菜了呜呜呜. 可以给大家参考一下,好像本来是加了音乐的,但是你们可能没有对应的音乐MP3文件,所以如 ...

  3. Python快速实现简易飞机大战小游戏

    参考:用python实现简单的飞机大战小游戏_化华桦的博客-CSDN博客_python飞机大战 敌机图片: 我方飞机: 子弹: 背景图: 主函数代码main.py: from PySide2 impo ...

  4. 飞机大战小游戏(超详细)

    偷学Python之最后的项目二:飞机大战小游戏(超详细) 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志.--苏轼 甜甜先说 这次用Python中的pygame模块来完成一个飞机大战的小游戏:基本思 ...

  5. 基于Java语言在窗体上实现飞机大战小游戏

    全套资料下载地址:https://download.csdn.net/download/sheziqiong/85594271 项目介绍 飞机大战:用 Java 语言在窗体上实现飞机大战小游戏,运行程 ...

  6. 【Java代码实现飞机大战小游戏】简单理解

    飞机大战 飞机大战小游戏历经10天完成,主要用到的就是我们面向对象部分的知识:类,封装,继承,多态,静态代码块等等内容+swing部分内容.所以即使你是java小白,也不用担心欧! 游戏说明:游戏有3 ...

  7. 【Java】Java基础飞机大战小游戏完整代码

    Java基础飞机大战小游戏完整代码 先来展示一下代码实现结果图 主函数ShootGame 初始化游戏原始背景图片,游戏人物图片,游戏开始结束图片:构建产生敌人算法:产生英雄机算法:发射子弹算法:判断是 ...

  8. 用C语言实现飞机大战小游戏

    我的个人博客:谋仁·Blog 该项目已上传至GitHub:点击跳转 文章目录 摘要 运行环境 整体功能思维导图 效果预览 具体功能的实现 图形界面:EasyX EasyX图形库简介 EasyX图形库的 ...

  9. C++ 飞机大战小游戏 EGE

    C++ EGE 实现飞机大战小游戏图形界面 飞机大战因为没有了地图的限制,所以相比较坦克大战而言稍微简单一些. 而游戏的可玩性和复杂度一般应该是成正比的. 但是飞机大战并没有因为地图上的省略而变得没有 ...

最新文章

  1. DHTML【7】--CSS
  2. 通过NVIDIA PilotNet,人人都能变成人工智能的老师
  3. unix网络编程——ioctl 函数的用法详解
  4. 机器人学习--室内定位的通信学科背景方法
  5. 2 RepMLP:卷积重参数化为全连接层进行图像识别 (Arxiv)
  6. Python+pandas+matplotlib可视化案例一则
  7. 奇怪,Python有的函数调用需要两对括号?(2)
  8. 遵循Java EE标准体系的开源GIS服务平台之三:数据发布与访问
  9. 灯亮怎么办_发动机故障灯亮了怎么办?看了这些,也许根本不用去4S店
  10. 腾讯CDC:用户流失原因调研四步经
  11. 【SCIRLab】ACL20 基于图注意力网络的多粒度机器阅读理解文档建模
  12. 简单java游戏代码_Java经典小游戏——贪吃蛇简单实现(附源码)
  13. i3wm nm-applet每次开机都要输入wifi密码的解决办法
  14. Unity自动设置keystore密匙库的信息
  15. 安卓玩机搞机技巧综合资源-----闲置手机当摄像头 当监控 上网课必备 多软件评测【十四】
  16. java徽章_java – 设计可插拔的点和徽章系统
  17. 下载SAPUI5 SDK
  18. 《C++ Primer Plus》读书笔记 第16章 string类和标准模板库
  19. TIM基本定时器——定时
  20. [杂言] GoodBye,2016

热门文章

  1. D1. RPD and Rap Sheet (Easy Version) (交互题+构造)
  2. 快递100API接口开发
  3. 遥感影像信息提取之—人工解译
  4. 粒子云我家云OMV集成固件
  5. Spark Streaming Direct Approach (No Receivers) 分析
  6. 解决:win10的ie11浏览器页面打开黑屏,无法显示
  7. 上海交通大学计算机系过敏意,上海交通大学-电子信息与电气工程学院-电子信息与电气工程学院...
  8. 锅炉给水泵flash_锅炉给水泵的主要结构
  9. Android图片预览框架PhotoViewer
  10. vim使用大全[转]