Qt QML实现弹球消砖块小游戏

news2025/7/12 18:26:00

前言

弹球消砖块游戏想必大家都玩过,很简单的小游戏,通过移动挡板反弹下落的小球,然后撞击砖块将其消除。本文使用QML来简单实现这个小游戏。
效果图:

在这里插入图片描述
在这里插入图片描述

正文

代码目录结构如下:
在这里插入图片描述
首先是小球部分,逻辑比较麻烦一点,需要检查与砖块的碰撞以及与挡板的碰撞,还要更新小球的轨迹位置,代码如下:
Ball.qml

import QtQuick 2.12

Rectangle {
    id: ball
    width: 15
    height: 15
    radius: width / 2
    color: "#FFFFFF"
    border.color: "#DDDDDD"
    border.width: 1
    
    // 引用游戏区域和挡板
    property var gameArea
    property var paddle
    
    // 球的速度和方向
    property real speedX: 0
    property real speedY: 0
    property real baseSpeed: 3
    
    // 信号:球丢失
    signal ballLost()
    
    // 重置球的位置和状态
    function reset() {
        x = gameArea.width / 2 - width / 2;
        y = gameArea.height / 2;
        speedX = 0;
        speedY = 0;
    }
    
    // 开始移动球
    function start() {
        if (speedX === 0 && speedY === 0) {
            // 随机初始方向,但确保向下
            var angle = (Math.random() * Math.PI / 2) + Math.PI / 4; // 45-135度之间
            speedX = Math.cos(angle) * baseSpeed;
            speedY = Math.sin(angle) * baseSpeed;
        }
    }
    
    // 检查与砖块的碰撞
    function checkBrickCollision() {
        for (var i = 0; i < gameArea.bricksRepeater.count; i++) {
            var brick = gameArea.bricksRepeater.itemAt(i);
            if (brick && !brick.destroyed) {
                var brickPos = brick.mapToItem(gameArea, 0, 0);
                
                if (x + width > brickPos.x && x < brickPos.x + brick.width &&
                    y + height > brickPos.y && y < brickPos.y + brick.height) {
                    
                    // 确定碰撞方向并反弹
                    var centerX = x + width / 2;
                    var centerY = y + height / 2;
                    var brickCenterX = brickPos.x + brick.width / 2;
                    var brickCenterY = brickPos.y + brick.height / 2;
                    
                    var dx = centerX - brickCenterX;
                    var dy = centerY - brickCenterY;
                    
                    if (Math.abs(dx / brick.width) > Math.abs(dy / brick.height)) {
                        // 水平碰撞
                        speedX = -speedX;
                    } else {
                        // 垂直碰撞
                        speedY = -speedY;
                    }
                    
                    // 击中砖块,立即消除当前碰撞的砖块
                    brick.hit();
                    return true;
                }
            }
        }
        return false;
    }
    
    // 检查与挡板的碰撞
    function checkPaddleCollision() {
        if (y + height >= paddle.y && y <= paddle.y + paddle.height &&
            x + width >= paddle.x && x <= paddle.x + paddle.width) {
            
            // 根据击中挡板的位置调整反弹角度
            var paddleCenter = paddle.x + paddle.width / 2;
            var ballCenter = x + width / 2;
            var relativePosition = (ballCenter - paddleCenter) / (paddle.width / 2);
            
            // 计算新的速度向量
            var angle = relativePosition * (Math.PI / 3); // 最大±60度
            var speed = Math.sqrt(speedX * speedX + speedY * speedY);
            speedX = Math.sin(angle) * speed;
            speedY = -Math.abs(Math.cos(angle) * speed); // 确保向上反弹
            
            // 稍微增加速度
            speedX *= 1.05;
            speedY *= 1.05;
            
            return true;
        }
        return false;
    }
    
    // 更新球的位置
    Timer {
        interval: 16 // 约60fps
        running: gameArea.gameRunning
        repeat: true
        onTriggered: {
            // 移动球
            x += speedX;
            y += speedY;
            
            // 检查墙壁碰撞
            if (x <= 0 || x + width >= gameArea.width) {
                speedX = -speedX;
                x = Math.max(0, Math.min(x, gameArea.width - width));
            }
            
            if (y <= 0) {
                speedY = -speedY;
                y = 0;
            }
            
            // 检查是否掉落
            if (y + height >= gameArea.height - 20 && !checkPaddleCollision()) {
                ballLost();
                return;
            }
            
            // 检查砖块碰撞
            checkBrickCollision();
            
            // 检查挡板碰撞
            checkPaddleCollision();
        }
    }
}

其次是砖块 Brick.qml

import QtQuick 2.12

Rectangle {
    id: brick
    radius: 3
    
    // 砖块状态
    property bool destroyed: false
    property int colorIndex: 0
    
    // 砖块颜色数组
    readonly property var colors: [
        "#FF5252", // 红色
        "#FFAB40", // 橙色
        "#FFEB3B", // 黄色
        "#66BB6A", // 绿色
        "#42A5F5"  // 蓝色
    ]
    
    // 砖块被销毁的信号
    signal brickDestroyed()
    
    // 设置砖块颜色
    color: colors[colorIndex % colors.length]
    border.color: Qt.darker(color, 1.2)
    border.width: 1
    visible: !destroyed
    
    // 砖块被击中
    function hit() {
        if (!destroyed) {
            destroyed = true;
            visible = false;
            brickDestroyed();
        }
    }
}

砖块击中后要销毁。

接着是挡板 Paddle.qml, 挡板可以通过键盘左右键进行移动,也可以直接使用鼠标进行左右拖动,代码如下:

import QtQuick 2.12

Rectangle {
    id: paddle
    width: 120
    height: 20
    radius: 10
    color: "#2196F3"
    border.color: "#1976D2"
    border.width: 1
    
    Component.onCompleted: {
        // 初始化时设置挡板居中
        x = (gameArea.width - width) / 2
    }
    
    // 引用游戏区域
    property var gameArea
    
    // 移动速度
    property int speed: 15
    property bool movingLeft: false
    property bool movingRight: false
    
    // 处理键盘按下事件
    function handleKeyPress(key) {
        if (key === Qt.Key_Left) {
            movingLeft = true;
        } else if (key === Qt.Key_Right) {
            movingRight = true;
        }
    }
    
    // 处理键盘释放事件
    function handleKeyRelease(key) {
        if (key === Qt.Key_Left) {
            movingLeft = false;
        } else if (key === Qt.Key_Right) {
            movingRight = false;
        }
    }
    
    // 鼠标控制
    MouseArea {
        anchors.fill: parent
        drag.target: parent
        drag.axis: Drag.XAxis
        drag.minimumX: 0
        drag.maximumX: gameArea.width - parent.width
    }
    
    // 定时器更新挡板位置
    Timer {
        interval: 16 // 约60fps
        running: (movingLeft || movingRight) && gameArea.gameRunning
        repeat: true
        onTriggered: {
            if (movingLeft) {
                paddle.x = Math.max(0, paddle.x - speed);
            }
            if (movingRight) {
                paddle.x = Math.min(gameArea.width - paddle.width, paddle.x + speed);
            }
        }
    }
}

以上是核心控件的完整代码。


本文Demo下载

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在实际应用中测量和调整直线导轨的预紧力?

在实际应用中&#xff0c;准确测量和调整直线导轨的预紧力对于保证设备的性能和精度至关重要&#xff0c;但测量和调整直线导轨的预紧力需要根据具体的导轨型号和结构来选择合适的方法。以下是一些常见的测量和调整方法&#xff1a; 1、使用压力传感器&#xff1a;在一些先进的…

YOLO11 使用入门

YOLO12 使用入门 1. 源码下载2. 权重下载3. 环境配置4. 例程测试4.1. 目标检测4.1.1. 源文件 model4.1.2. 结果Results4.1.3. 边界框 Boxes 2.2. 图像分割4.2.1. 推理 model.predict4.2.2. 掩码 Masks 1. 源码下载 之前介绍了《目标检测 YOLOv5 使用入门》 现在是 2024.12.2…

汽车感性负载-智能高边钳位能量计算

随着汽车电子技术的发展&#xff0c;新的电子电气架构下&#xff0c;越来越多的执行部件在车身出现&#xff0c;比如电磁阀、风机、水泵、油泵、雨刮继电器等常用的执行器&#xff0c; 它们一般都表现为感性特点。驱动这些负载的最简单和最常见的方法是将它们连接到高边侧开关(…

基于Python+Flask+MySQL+HTML的爬取豆瓣电影top-250数据并进行可视化的数据可视化平台

FlaskMySQLHTML 项目采用前后端分离技术&#xff0c;包含完整的前端&#xff0c;以flask作为后端 Pyecharts、jieba进行前端图表展示 通过MySQL收集格列数据 通过Pyecharts制作数据图表 这是博主b站发布的详细讲解&#xff0c;感兴趣的可以去观看&#xff1a;【Python爬虫可…

七大常用智能家居协议对比

如果您不知道在项目中使用哪种智能家居通信协议&#xff0c;那么进入智能家居行业可能会很困难。如果没有合适的协议将其集成到智能家居生态系统中&#xff0c;智能家居设备将无法正常工作。否则&#xff0c;您将面临硬件和软件无法满足最终用户期望的风险。协议选择不当可能会…

996引擎-问题处理:缺失特效分割文件 ModelAtlasSplitConfigs

通常我们买的资源都是带会 ModelAtlasSplitConfigs.txt 或 sceneAtlasSplitConfigs.txt 的 但有时确实找不到的话&#xff0c;是可以用996工具生成的&#xff1a;

异步加载错误如何解决

首先是 提供两张图 如果数据过多的情况下我在所内和住家形式频繁的来回切换 导致数据展示的不一样 大家是不是有这样的问题 这个是导致了数据展示有问题的情况 住家的情况本来是没有几层的 下面我帮大家解决一下 // 防止异步延迟 const Noop () > { } const lhl (resDa…

R语言零基础系列教程-01-R语言初识与学习路线

代码、讲义、软件回复【R语言01】获取。 R语言初识 R是一个开放的统计编程环境&#xff0c;是一门用于统计计算和作图的语言。“一切皆是对象”&#xff0c;数据、函数、运算符、环境等等都是对象。易学&#xff0c;代码像伪代码一样简洁&#xff0c;可读性高强大的统计和可视…

自动化测试-网页聊天室

项目介绍&#xff1a; 针对基于WebSocket协议的网页端即时通讯系统&#xff0c;主导设计并实施全流程自动化测试方案。通过构建模块化测试框架&#xff0c;完成对核心业务场景&#xff08;用户登录鉴权、消息同步、实时聊天等&#xff09;的自动化验证&#xff0c;最终达成测试…

创新实践分享:基于边缘智能+扣子的智能取物机器人解决方案

在 2024 年全国大学生物联网设计竞赛中&#xff0c;火山引擎作为支持企业&#xff0c;不仅参与了赛道的命题设计&#xff0c;还为参赛队伍提供了相关的硬件和软件支持。以边缘智能和扣子的联合应用为核心&#xff0c;参赛者们在这场竞赛中展现出了卓越的创新性和实用性&#xf…

【蓝桥杯】省赛:神奇闹钟

思路 python做这题很简单&#xff0c;灵活用datetime库即可 code import os import sys# 请在此输入您的代码 import datetimestart datetime.datetime(1970,1,1,0,0,0) for _ in range(int(input())):ls input().split()end datetime.datetime.strptime(ls[0]ls[1],&quo…

使用kubeadm方式以及使用第三方工具sealos搭建K8S集群

目录 kubeadm方式: 一、安装要求 二、环境准备 二、安装Docker、kubeadm、kubelet 1、安装Docker &#xff08;1&#xff09;首先配置一下Docker的阿里yum源 &#xff08;2&#xff09;然后用yum 方式安装docker &#xff08;3&#xff09;配置Docker镜像加速器 &#…

2025 linux系统资源使用率统计docker容器使用率统计docker监控软件Weave Scope安装weavescope

1.Weave Scope介绍 Weave Scope 是一款用于监控和可视化 Docker 容器、Kubernetes 集群以及分布式应用的强大工具。它的设计目标是帮助开发者和运维人员更好地理解和管理复杂的微服务架构。以下是 Weave Scope 的主要优点&#xff1a; 1. 实时可视化 Weave Scope 提供了一个直…

通过特征值和特征向量实现的图像压缩和特征提取

前文&#xff0c;我们在学习人工智能的线性代数基础的时候&#xff0c;就了解到&#xff0c;矩阵在人工智能中被广泛使用&#xff0c;接下来我们就从大家非常常见的图像开始&#xff0c;深度理解矩阵在人工智能中的应用。有关线性代数基础的文章可以看的我CSDN:人工智能中的线性…

【eNSP基础使用教程-1】

座右铭: 纵有疾风起&#xff0c;人生不言弃。 文章目录 前言一、更改设备名称指令1、双击路由器进入2、 进入系统视图3、更改设备名称为R14、使用同样的办法修改路由器R2、R3 二、配置路由物理接口的IP 地址1、查看R1路由器当前接口IP 地址配置与路由表2、查看路由器上的路由表…

机器学习常见激活函数

激活函数的作用 引入非线性因素 若神经网络仅由线性层构成&#xff0c;那么无论网络的层数有多少&#xff0c;其整体的输出依然是输入的线性组合。这样的网络只能拟合线性函数&#xff0c;在处理复杂的非线性问题&#xff08;如语音识别、图像分类&#xff09;时能力十分有限。…

netcore publish报错 error CS1056: Unexpected character

问题&#xff1a;jenkins netcore publish报错 检查文件编码&#xff0c;发现是:GB2312。转换为&#xff1a;UTF-8-BOM。 问题解决 。

网页制作14-Javascipt时间特效の显示动态日期

<!doctype html> <html> <head> <meta charset"utf-8"> <title>动态日期</title> </head><script>var today new Date();//获取时间var ytoday.getFullYear();//截取年var mtoday.getMonth();//截取月份,返回0~11v…

《高效迁移学习:Keras与EfficientNet花卉分类项目全解析》

从零到精通的迁移学习实战指南&#xff1a;以Keras和EfficientNet为例 一、为什么我们需要迁移学习&#xff1f; 1.1 人类的学习智慧 想象一下&#xff1a;如果一个已经会弹钢琴的人学习吉他&#xff0c;会比完全不懂音乐的人快得多。因为TA已经掌握了乐理知识、节奏感和手指…

【单片机】嵌入式系统的硬件与软件特性

嵌入式系统的软件结构 嵌入式系统的软件结构一般分为 不带操作系统&#xff08;Bare Metal&#xff09; 和 带操作系统&#xff08;RTOS / Linux&#xff09; 两种。不同的软件架构适用于不同的应用场景&#xff0c;如 简单控制系统、实时控制系统、物联网、工业自动化等。 嵌…