【QT】飞机大战

0 项目简介

飞机大战是我们大家所熟知的一款小游戏,本教程就是教大家如何制作一款自己的飞机大战

首先我们看一下效果图

玩家控制一架小飞机,然后自动发射子弹,如果子弹打到了飞下来的敌机,则射杀敌机,并且有爆炸的特效

接下来再说明一下案例的需求,也就是我们需要实现的内容

  • 滚动的背景地图

  • 飞机的制作和控制

  • 子弹的制作和射击

  • 敌机的制作

  • 碰撞检测

  • 爆炸效果

  • 音效添加

1 设置主场景

(1)创建工程,class name为MainScene

(2)定义一个配置文件,专门定义一些相关的参数(config.h);

(3)主场景目前只需要固定界面的大小和标题即可,即config.h中定义以下数据:

/***********************游戏数据配置***********************************/
#define GAME_WIDTH  512                             // 宽度
#define GAME_HEIGHT 768                             // 高度
#define GAME_TITLE "飞机大战 v1.0"                   // 标题

(4)在MainScene.h中定义初始化游戏场景的函数initScene,并在mainScene.cpp实现

// 初始化游戏场景
void MainScene::initScene()
{//初始化窗口大小setFixedSize(GAME_WIDTH,GAME_HEIGHT);//设置窗口标题setWindowTitle(GAME_TITLE);
}

(5)在MainScene的构造函数中调用initScene函数。运行程序,此时界面出现

2 资源导入

(1)资源导入见:【QT】资源文件导入_复制其他项目中的文件到qt项目中_StudyWinter的博客-CSDN博客

(2)将qrc文件生成rcc二进制文件,利用cmd打开终端,定位到res.qrc的目录下,输入命令

rcc -binary .\res.qrc -o plane.rcc

(3)将生成好的rcc文件,放入到debug同级目录中一份;

(4)注册二进制文件。在config.h中追加

#define GAME_RES_PATH "./plane.rcc"                 // 资源路径

在main.cpp中修改代码

#include "mainscene.h"
#include <QResource>
#include <QApplication>
#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();
}

此时,qrc文件已经没用了,删除即可!最简单的删除方式就是 .pro工程文件中删除代码

删除以下代码:
RESOURCES += \res.qrc

(5)添加图标资源。配置文件config.h中追加代码

虚拟资源路径语法如下:

" : + 前缀名 + 文件路径 "

#define GAME_ICON ":/res/app.ico"                   // 图标路径

在mainScene.cpp的 initScene函数中追加代码:

// 加载图片
setWindowIcon(QIcon(GAME_ICON));    // 加头文件 #include <QIcon>

运行测试:

3 地图滚动

(1)创建地图类Map;

(2)在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

(3)在配置文件config.h中添加参数

/*************************地图信息***********************************/
#define MAP_PATH ":/res/img_bg_level_3.jpg"        // 地图1图片路径
#define MAP_SCROLL_SPEED 2                          // 地图滚动速度

(4)在Map.cpp中实现成员函数(这里就涉及了业务逻辑)

#include "map.h"
#include "config.h"Map::Map()
{// 加载地图对象,两张图无缝衔接m_map1.load(MAP_PATH);m_map2.load(MAP_PATH);// 设置地图起始y坐标// 窗口是(0.0)点,第一张图在上面,所以y轴的坐标是-GAME_HEIGHTm_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;}
}

(5)添加定时器

关于定时器详见:【QT】定时器_qt 定时器-CSDN博客

在mainScene.h中添加新的定时器对象

QTimer m_Timer;

在 config.h中添加 屏幕刷新间隔

#define GAME_RATE  10                               //刷新间隔,帧率 单位毫秒

在MainScene.cpp的initScene中追加代码

  // 定时器设置m_timer.setInterval(GAME_RATE);

(6)启动定时器实现地图滚动

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

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

在MainScene.cpp中实现成员函数

// 启动游戏  用于启动定时器对象
void MainScene::playGame()
{// 启动定时器m_timer.start();// 监听定时器connect(&m_timer, &QTimer::timeout, this, [=]() {// 更新游戏中元素的坐标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);
}

在MainScene的构造函数中调用启动游戏函数

MainScene::MainScene(QWidget *parent): QWidget(parent)
{//初始化场景initScene();// 启动游戏playGame();
}

测试运行游戏,实现地图滚动

4 创建英雄飞机

(1)创建英雄飞机类HeroPlane;

(2)在英雄飞机中添加成员函数和属性

HeroPlane.h

#ifndef HEROPLANE_H
#define HEROPLANE_H
#include <QPixmap>
#include <QRect>
#include "bullet.h"
#include "config.h"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;
};#endif // HEROPLANE_H

(2)在配置文件config.h中添加参数

/************************飞机配置数据***********************************/
#define HERO_PATH ":/res/hero2.png"                 // 飞机图片路径

(3)在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);
}void HeroPlane::shoot()
{}// 设置飞机位置
void HeroPlane::setPosition(int x, int y)
{m_x = x;m_y = y;m_rect.moveTo(m_x, m_y);
}

(4)创建飞机并显示。MainScene.h中追加

    // 飞机对象HeroPlane m_hero;

在MainScene.cpp的paintEvent中追加代码

  // 绘制英雄飞机painter.drawPixmap(m_hero.m_x, m_hero.m_y, m_hero.m_plane);

此时测试,飞机已经可以显示在屏幕中了

(5)利用鼠标拖拽飞机。在MainScene.h中添加鼠标事件

 // 鼠标移动事件void mouseMoveEvent(QMouseEvent*);

重写鼠标移动事件

// 鼠标移动事件
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);
}

测试飞机可以拖拽

5 子弹制作

6 玩家发射子弹

7 敌机制作

8 碰撞检测

9 爆炸效果

10 音效添加

11 打包发布

资源来自:01 飞机大战项目演示以及需要分析_哔哩哔哩_bilibili

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/191320.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ESP32 Arduino实战基础篇-生成 PWM 信号

在本教程中,我们将向您展示如何使用 Arduino IDE 通过 ESP32 生成 PWM 信号。作为示例,我们将构建一个简单的电路,使用 ESP32 的 LED PWM 控制器对 LED 进行调光。我们还将向您展示如何同时在不同的 GPIO 上获取相同的 PWM 信号。 在继续本教程之前,您应该在 Arduino IDE 中…

nvm工具解决nodejs版本切换问题

常见版本问题 npm启动vite项目报错&#xff0c;信息如下 npm run dev> my-vue-app0.0.0 dev D:\data\code\document-assistant-web > vitefile:///D:/data/code/document-assistant-web/node_modules/vite/bin/vite.js:7await import(source-map-support).then((r) >…

国际阿里云:Windows实例中数据恢复教程!!!

在处理磁盘相关问题时&#xff0c;您可能会碰到操作系统中数据盘分区丢失的情况。本文介绍了Windows系统下常见的数据盘分区丢失的问题以及对应的处理方法&#xff0c;同时提供了使用云盘的常见误区以及最佳实践&#xff0c;避免可能的数据丢失风险。 前提条件 已注册阿里云账…

两数之和问题

题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按任意顺…

Java 简单实现一个 UDP 回显服务器

文章目录 UDP 服务端UDP 客户端实现效果UDP 服务端(实现字典功能)总结 UDP 服务端 package network;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException;public class UdpEchoServer {private Da…

监控和数据采集软件架构和详细设计

介绍 监控和数据采集软件通过提供实时监控、数据收集和分析功能&#xff0c;在各个行业中发挥着至关重要的作用。这些软件应用程序可帮助企业收集有价值的见解、优化流程并做出明智的决策。在本文中&#xff0c;我们将探讨监测和数据采集软件的软件架构、编程技术和详细设计规范…

在 Vue3 中使用 mitt 进行组件通信

npm 包地址 mitt 是一个轻量级的 JavaScript 事件触发器&#xff0c; 只有200b。有基本的事件触发、订阅和取消订阅功能&#xff0c;还支持用命名空间来进行更高级的事件处理。 功能特点&#xff1a; Microscopic —— weighs less than 200 bytes gzippedUseful —— a wil…

【Liunx】DHCP服务

【Liunx】DHCP服务 DHCP概述A.安装dhcpB.查看配置文件C.修改配置文件 DHCP概述 DHCP(Dynamic Host Configuration Protocol)i动态主机配置协议 DHCP是由Internet工作任务小组设计开发的&#xff0c;专门用于为TCP/IP网络中的计算机自动分配TCP/IP参数的协议。 口使用DHCP服务的…

在PyTorch中使用CUDA, pytorch与cuda不同版本对应安装指南,查看CUDA版本,安装对应版本pytorch

目录 1 查看本机CUDA版本 2 查看对应CUDA的对应pytorch版本安装 3 用pip 安装 4 用conda安装 5 验证安装 在PyTorch中使用CUDA&#xff0c;根据你的具体环境和需求调整版本号&#xff0c;确保安装的PyTorch版本与你的CUDA版本兼容。 在PyTorch中使用CUDA&#xff0c;你需…

StackExchange.Redis 高并发下timeout超时问题如何解决?

查看服务端程序负载还行&#xff0c;根据打印的连接看到一知半懂&#xff0c;按GitHub的issue提示&#xff0c;这2个Busy的数量不能比Min的大&#xff0c;即要提示Min的数值; 的各个字段&#xff1a; Timeout performing EXEC (1000ms): 表示在执行一个事务&#xff08;MULTI..…

Django ModelSerializer 实现自定义验证详解

随着 Web 开发的日益复杂化&#xff0c;对数据验证的需求也日益增加。Django REST framework 提供了一套强大的、灵活的验证系统&#xff0c;帮助开发者轻松处理各种复杂情况。本文将重点探讨 Django ModelSerializer 中如何实现自定义验证。 1. 简介 Django ModelSerializer…

JVM源码剖析之软、弱、虚引用的处理细节

目录 写在前面&#xff1a; 源码剖析&#xff1a; Java层面&#xff1a; JVM层面&#xff1a; 使用危险点&#xff1a; 总结&#xff1a; 版本信息&#xff1a; jdk版本&#xff1a;jdk8u40 垃圾回收器&#xff1a;Serial new/old 写在前面&#xff1a; 不同的垃圾回收…

8255 boot介绍及bring up经验分享

这篇文章会简单的介绍8255的启动流程&#xff0c;然后着重介绍8255在实际项目中新硬件上的bring up工作&#xff0c;可以给大家做些参考。 8255 boot介绍 下面这些信息来自文档&#xff1a;《QAM8255P IVI Boot and CoreBSP Architecture Technical Overview》 80-42847-11 R…

2023年开发语言和数据库排行

2023年开发语言和数据库排行 一、开发语言相关1. Python1.1 Python优点1.2 Python缺点1.3 Python应用领域 2. C 语言2.1 C 语言优点2.2 C 语言缺点2.3 C语言应用领域 3. Java3.1 Java 优点3.2 Java缺点3.3 Java应用场景 4. C4.1 C 优点4.2 C 缺点4.3 C 应用场景 5. C#5.1 C# 优…

模拟退火算法MATLAB实现

介绍 算法试图随着控制参数T的降低&#xff0c;使目标函 数值f&#xff08;内能E&#xff09;也逐渐降低&#xff0c;直至趋于全局最 小值&#xff08;退火中低温时的最低能量状态&#xff09;&#xff0c;算法 工作过程就像固体退火过程一样。 Metropolis准则——–以概率接受…

ROS话题(Topic)通信:通信模型、Hello World与拓展

文章目录 一、话题通讯模型二、Topic Hello World2.1 创建并初始化功能包2.2 确定Topic名称及消息格式2.3 实现发布者与订阅者&#xff08;C版&#xff09;2.4 实现发布者与订阅者&#xff08;Python版&#xff09;2.5 关于Topic Hello World的注意 拓展1&#xff1a;devel下其…

预览PDF并显示当前页数

这里写目录标题 步骤实例实例效果图 步骤 1.安装依赖 npm install --save vue-pdf2.在需要的页面&#xff0c;引入插件 import pdf from vue-pdf3.使用 单页pdf可以直接使用 <pdf :src"获取到的pdf地址"></pdf>多页pdf通过循环实现 html标签部分 &l…

Banana Pi BPI-M5 Boot Log 导出说明

准备&#xff1a; Preparation: 1、 一块bpi的开发板&#xff0c;一根ttl的串口线&#xff0c;以及一张烧录好镜像的sd/tf卡&#xff08;烧录到eMMC也行&#xff09;。 1. A BPI development board, a TTL serial port cable, and an SD/TF card with a burned image (it ca…

高并发架构设计(三大利器:缓存、限流和降级)

引言 高并发背景 互联网行业迅速发展&#xff0c;用户量剧增&#xff0c;系统面临巨大的并发请求压力。 软件系统有三个追求&#xff1a;高性能、高并发、高可用&#xff0c;俗称三高。三者既有区别也有联系&#xff0c;门门道道很多&#xff0c;全面讨论需要三天三夜&#…

Rust编程中的共享状态并发执行

1.共享状态并发 虽然消息传递是一个很好的处理并发的方式&#xff0c;但并不是唯一一个。另一种方式是让多个线程拥有相同的共享数据。在学习Go语言编程过程中大家应该听到过一句口号:"不要通过共享内存来通讯"。 在某种程度上&#xff0c;任何编程语言中的信道都类…