基于PyQt5的图形化界面开发——打砖块

news2024/11/25 0:41:09

0. 前言

本文使用 PyQt5实现一个打砖块小游戏

在这里插入图片描述

操作系统:Windows10 专业版

开发环境:Pycahrm Comunity 2022.3

Python解释器版本:Python3.8

第三方库:PyQt5

1. 砖块类定义

在构造函数__init__中,Brick类接受两个参数x和y,表示砖块初始化时的位置。通过调用super().__init__来初始化QGraphicsRectItem的基类,传入参数0, 0, 40, 20来设置砖块的初始大小。然后使用setPos方法将砖块的位置设置为给定的x和y。

接下来,使用setBrush方法设置砖块的颜色为红色。QColor(150, 0, 0)表示红色,其中150表示红色通道的亮度,而0表示绿色和蓝色通道的亮度为0。

使用setFlag方法设置QGraphicsItem.ItemIsSelectable标志,表示砖块可以被选中。

destroy方法用于移除砖块。在该方法中,使用self.scene.removeItem(self)将砖块从场景中移除。

class Brick(QtWidgets.QGraphicsRectItem):
    def __init__(self, x, y):
        super(Brick, self).__init__(0, 0, 40, 20)
        self.setPos(x, y)
        self.setBrush(QtGui.QColor(150, 0, 0))
        self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True)

    def destroy(self):
        scene.removeItem(self)

2. 挡板类定义

这段代码定义了一个名为Paddle的类,该类继承自QGraphicsRectItem,用于表示打砖块游戏中的挡板。

在函数__init__中,Paddle类使用super().__init__方法来初始化QGraphicsRectItem的基类,设置挡板的初始大小为80像素宽和10像素高。然后使用setPos方法将挡板的位置设置为(360, 540)。

接下来,使用setBrush()方法设置挡板的颜色为蓝色。QColor(0, 0, 150)表示蓝色,其中0表示红色和绿色通道的亮度为0,而150表示蓝色通道的亮度为150。

使用setFlag方法设置QGraphicsItem.ItemIsMovable标志,表示挡板可以通过鼠标拖动来移动。

moveLeft方法用于将挡板向左移动。在该方法中,首先判断当前挡板的x坐标是否大于等于10,以确保挡板不会超出左边界。如果满足条件,则使用setPos方法将挡板的x坐标减去20,实现向左移动。

moveRight方法用于将挡板向右移动。在该方法中,首先判断当前挡板的x坐标是否小于等于710,以确保挡板不会超出右边界。如果满足条件,则使用setPos方法将挡板的x坐标加上20,实现向右移动。

class Paddle(QtWidgets.QGraphicsRectItem):
    def __init__(self):
        super(Paddle, self).__init__(0, 0, 80, 10)
        self.setPos(360, 540)
        self.setBrush(QtGui.QColor(0, 0, 150))
        self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)


    def moveLeft(self):
        if self.x() >= 10:
            self.setPos(self.x() - 20, self.y())

    def moveRight(self):
        if self.x() <= 710:
            self.setPos(self.x() + 20, self.y())

3. 碰撞检测

定义名为Ball的类,该类继承自QGraphicsEllipseItem,用于表示打砖块游戏中的小球。

在构造函数__init__中,Ball类使用super().__init__方法来初始化QGraphicsEllipseItem的基类,设置小球的初始大小为20像素直径。然后使用setPos方法将小球的位置设置为(390, 520)。

接下来,使用setBrush方法设置小球的颜色为绿色。QColor(0, 150, 0)表示绿色,其中0表示红色和蓝色通道的亮度为0,而150表示绿色通道的亮度为150。

Ball类还定义了dx和dy两个变量,分别表示小球在x轴和y轴上的速度。在构造函数中,将dx和dy初始化为-5,表示小球在水平和垂直方向上的速度为-5。

score变量用于记录游戏得分,初始值为0。

advance方法用于在每一帧更新时,更新小球的位置和状态。首先判断是否是更新阶段,如果不是,则直接返回。然后通过改变小球的位置,使用setPos方法将小球的x坐标增加dx,y坐标增加dy,实现小球的移动。

接下来,进行碰撞检测,判断小球是否与边界、挡板或砖块发生碰撞,并根据碰撞结果进行相应的处理。

class Ball(QtWidgets.QGraphicsEllipseItem):
    def __init__(self):
        super(Ball, self).__init__(0, 0, 20, 20)
        self.setPos(390, 520)
        self.setBrush(QtGui.QColor(0, 150, 0))
        self.dx = -5
        self.dy = -5
        self.score = 0

    def advance(self, phase):
        if not phase:
            return

        self.setPos(self.x() + self.dx, self.y() + self.dy)

        # 左右边界反弹
        if self.x() <= 0 or self.x() >= 780:
            self.dx *= -1

        # 上边界反弹
        if self.y() <= 0:
            self.dy *= -1

        # 下边界游戏结束
        if self.y() >= 600:
            exit()

        # 触碰挡板反弹
        if self.collidesWithItem(paddle):
            self.dy *= -1

        # 计分数组
        for brick in bricks:
            if self.collidesWithItem(brick):
                brick.destroy()
                bricks.remove(brick)
                self.dy *= -1
                self.score += 10
                break

4. 小球和游戏初始化

这段代码定义了一个名为MainScene的类,它是基于QtWidgets.QGraphicsScene的子类。这个类用来创建游戏场景,并包括初始化场景大小、添加挡板、添加球、初始化砖块位置和计分面板等功能。

在初始化方法__init__中,设置了场景的大小为800x600,并声明了全局变量bricks、paddle、ball和score。然后创建了一个Paddle对象,并将其添加到场景中,接着创建了一个Ball对象,并将其也添加到场景中。

接下来使用一个循环来初始化砖块的位置,创建了20个Brick对象,并根据位置将其添加到场景中,并将这些砖块对象存储在bricks列表中。

在代码的最后,创建了一个QLabel对象score用于显示得分,并设置其位置和字体样式,然后将其添加到场景中。同时定义了一个keyPressEvent方法,用来捕捉键盘按键事件,当按下左方向键时,调用paddle对象的moveLeft方法,当按下右方向键时,调用paddle对象的moveRight方法。

在advance方法中,利用父类的advance方法来更新场景状态,同时根据当前球的得分来更新显示的得分文本。

class MainScene(QtWidgets.QGraphicsScene):
    def __init__(self, parent=None):
        super(MainScene, self).__init__(parent)
        self.setSceneRect(0, 0, 800, 600)

        global bricks, paddle, ball, score

        paddle = Paddle()
        self.addItem(paddle)

        ball = Ball()
        self.addItem(ball)


        # 初始化砖块位置
        bricks = []
        for i in range(20):
            brick = Brick((i % 4) * 200, (i // 4) * 40)

            if random.randint(0,2):
                self.addItem(brick)
                bricks.append(brick)

        score = QtWidgets.QLabel()
        # 设置得分面板位置
        score.move(350,580)
        score.setText("Score: 00  ")
        score.setFont(QtGui.QFont("Arial", 12, QtGui.QFont.Bold))
        self.addWidget(score)

    def keyPressEvent(self, event):
        # 左方向键
        if event.key() == QtCore.Qt.Key_Left:
            paddle.moveLeft()
        # 右方向键
        elif event.key() == QtCore.Qt.Key_Right:
            paddle.moveRight()

    # 计分显示
    def advance(self):
        super(MainScene, self).advance()
        score.setText("Score: {}  ".format(str(ball.score)))

5. 完整代码

只需要这一个文件就能运行:
main.py

from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
import random


class Brick(QtWidgets.QGraphicsRectItem):
    def __init__(self, x, y):
        super(Brick, self).__init__(0, 0, 40, 20)
        self.setPos(x, y)
        self.setBrush(QtGui.QColor(150, 0, 0))
        self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True)

    def destroy(self):
        scene.removeItem(self)


class Paddle(QtWidgets.QGraphicsRectItem):
    def __init__(self):
        super(Paddle, self).__init__(0, 0, 80, 10)
        self.setPos(360, 540)
        self.setBrush(QtGui.QColor(0, 0, 150))
        self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)


    def moveLeft(self):
        if self.x() >= 10:
            self.setPos(self.x() - 20, self.y())

    def moveRight(self):
        if self.x() <= 710:
            self.setPos(self.x() + 20, self.y())


class Ball(QtWidgets.QGraphicsEllipseItem):
    def __init__(self):
        super(Ball, self).__init__(0, 0, 20, 20)
        self.setPos(390, 520)
        self.setBrush(QtGui.QColor(0, 150, 0))
        self.dx = -5
        self.dy = -5
        self.score = 0

    def advance(self, phase):
        if not phase:
            return

        self.setPos(self.x() + self.dx, self.y() + self.dy)

        # 左右边界反弹
        if self.x() <= 0 or self.x() >= 780:
            self.dx *= -1

        # 上边界反弹
        if self.y() <= 0:
            self.dy *= -1

        # 下边界游戏结束
        if self.y() >= 600:
            exit()

        # 触碰挡板反弹
        if self.collidesWithItem(paddle):
            self.dy *= -1

        # 计分数组
        for brick in bricks:
            if self.collidesWithItem(brick):
                brick.destroy()
                bricks.remove(brick)
                self.dy *= -1
                self.score += 10
                break


class MainScene(QtWidgets.QGraphicsScene):
    def __init__(self, parent=None):
        super(MainScene, self).__init__(parent)
        self.setSceneRect(0, 0, 800, 600)

        global bricks, paddle, ball, score

        paddle = Paddle()
        self.addItem(paddle)

        ball = Ball()
        self.addItem(ball)


        # 初始化砖块位置
        bricks = []
        for i in range(20):
            brick = Brick((i % 4) * 200, (i // 4) * 40)

            if random.randint(0,2):
                self.addItem(brick)
                bricks.append(brick)

        score = QtWidgets.QLabel()
        # 设置得分面板位置
        score.move(350,580)
        score.setText("Score: 00  ")
        score.setFont(QtGui.QFont("Arial", 12, QtGui.QFont.Bold))
        self.addWidget(score)

    def keyPressEvent(self, event):
        # 左方向键
        if event.key() == QtCore.Qt.Key_Left:
            paddle.moveLeft()
        # 右方向键
        elif event.key() == QtCore.Qt.Key_Right:
            paddle.moveRight()

    # 计分显示
    def advance(self):
        super(MainScene, self).advance()
        score.setText("Score: {}  ".format(str(ball.score)))


if __name__ == '__main__':
    app = QApplication([])
    window = QMainWindow()
    window.setWindowTitle("打砖块小游戏 ——By IoT_H2")

    view = QtWidgets.QGraphicsView()
    scene = MainScene(window)
    view.setScene(scene)
    window.setCentralWidget(view)

    timer = QtCore.QTimer()
    timer.timeout.connect(scene.advance)
    timer.start(20)

    window.show()
    sys.exit(app.exec_())

6. 运行效果演示

由于我是使用了random库生成砖块位置,所以每一局场景都是不同的:
在这里插入图片描述

在这里插入图片描述

7. Pyinstaller 编译exe程序

在这里插入图片描述
输入这个:

Pyinstaller -F main.py

在这里插入图片描述
等待编译完成

在./dist可以找到main.exe
在这里插入图片描述
双击它就能进入打砖块小游戏啦

PyQt5

基于PyQt5的图形化界面开发——天气应用

基于PyQt5的图形化界面开发——自制MQTT客户端

基于PyQt5的图形化界面开发——Windows内存资源监视助手[附带编译exe教程]

基于PyQt5的图形化界面开发——模拟医院管理系统

基于PyQt5的图形化界面开发——自制ssh工具

基于PyQt5的图形化界面开发——PyQt示例_计算器

基于PyQt5的图形化界面开发——PyQt示例_扫雷

基于PyQt5的图形化界面开发——自制Redis图形化客户端(文末附源码)

基于PyQt5的图形化界面开发——堆栈动画演示

基于PyQt5的图形化界面开发——队列动画演示

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

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

相关文章

自学成为一名顶级黑客(网络安全)

一、自学网络安全学习的误区和陷阱 1.不要试图先成为一名程序员&#xff08;以编程为基础的学习&#xff09;再开始学习 行为&#xff1a;从编程开始掌握&#xff0c;前端后端、通信协议、什么都学。 缺点&#xff1a;花费时间太长、实际向安全过渡后可用到的关键知识并不多。…

加密与解密 解密篇 逆向分析技术 (一) 栈/调用约定

目录 逆向是什么 32位软件逆向技术 1.启动函数 2.函数 函数的识别 函数的参数 利用栈进行传递 下面是通过esp来寻址 通过寄存器来传递参数 例子 例子 函数的返回值 例子 例子 逆向是什么 将可执行程序反汇编 通过分析反汇编代码来理解其代码功能&#xff08;各个…

慢速减压控制技术在预防同步辐射光源和原位透射电镜氮化硅窗口膜真空中破裂的应用

摘要&#xff1a;氮化硅薄膜窗口广泛应用于同步辐射光源中的扫描透射软X射线显微镜和原位透射电镜&#xff0c;但氮化硅薄膜只有几百纳米的厚度&#xff0c;很容易因真空抽取初期的快速压差变化造成破裂。为此&#xff0c;本文提出了线性缓变压力控制解决方案&#xff0c;即控制…

【小数据处理】从日志中获取json数据的处理

写在头上 本次分析的数据来源是SpringBoot服务输出的logback日志。具体配置参考&#xff1a; 处理工具:Notepad v7.6。处理的日志内容不易过大&#xff0c;Notepad能打开电脑不卡最好&#xff08;100M以内吧&#xff09;。如果实在过大&#xff0c;先从日志源头进行截取&…

【javaEE面试题(五)在JMM(Java Memory Model (Java 内存模型))下谈volatile的作用】【保证内存可见 和 指令有序】

volatile的作用 JMM下volatile作用 volatile 能保证内存可见性 volatile 修饰的变量, 能够保证 “内存可见性”. 代码在写入 volatile 修饰的变量的时候 改变线程工作内存中volatile变量副本的值将改变后的副本的值从工作内存刷新到主内存 代码在读取 volatile 修饰的变量的时…

微信小程序上线与发布图文步骤操作

1.上传代码 打开微信小程序&#xff0c;在微信开发者工具的工具栏中单击“上传”按钮&#xff0c;页面中弹出提示框&#xff0c;根据提示填写相应的信息&#xff0c;然后单击“上传”按钮&#xff0c;即可上传代码。 2.查看上传代码之后的版本 登录微信小程序管理后台&…

【docker】部署svn服务器,docker安装部署svn服务器

话不多说直接上步骤&#xff01; 1.下载镜像&#xff0c;创建容器 # 下载镜像 docker pull elleflorio/svn-server # 创建svn仓库目录&#xff0c;进入svn仓库目录 mkdir -p /var/svn # 创建svn服务容器&#xff0c;把容器中的svn仓库映射到本机&#xff0c;并映射3690端口 d…

基于深度学习的高精度安全帽及背心检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度安全帽及背心检测识别系统可用于日常生活中或野外来检测与定位安全帽及背心目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的安全帽及背心目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系…

动手学深度学习——线性回归(原理解释+代码详解)

目录 1、线性回归2、线性回归模型2.1 线性模型2.2 损失函数2.2.1 平方差损失函数2.2.2 整个数据集上的损失函数 2.3 随机梯度下降2.4 用模型进行预测 3、线性回归的简单实现3.1 生成数据集3.2 读取数据集3.3 初始化模型参数3.4 定义模型3.5 定义损失函数3.6 定义优化算法3.7 训…

H3C-Cloud Lab实验-OSPF配置实验

一、实验拓扑图 实验需求&#xff1a; 1、按照图示配置 IP 地址 2、按照图示分区域配置 OSPF &#xff0c;实现全网互通 3、为了路由结构稳定&#xff0c;要求路由器使用环回口作为 Router-id&#xff0c;ABR 的环回口宣告进骨干区域 4、掌握OSPF初始化流程、路由表学习的过…

基于linux下的高并发服务器开发(第一章)- GDB调试(2)1.14

&#xff08;1&#xff09;执行 gcc test.c -o test -g &#xff0c;生成test文件 &#xff08;2&#xff09;gdb test &#xff08;3&#xff09;list 查看当前文件代码 list/l &#xff08;从默认位置显示&#xff09; &#xff08;4&#xff09;l 20 list/l 行号 &#xf…

kafka(一)

一&#xff1a;kafka架构介绍 1. Brokers kafka集群包括一个或者多个服务器&#xff0c;服务器的节点叫做broker。 2. Topic 类似于数据库中的table。物理上不通的topic会分开存储。一个topic的消息会存储在多个broker上。但是在读取的时候&#xff0c;只要选择好topic&…

Centos Stream9安装Neovim的详细过程

Centos Stream9下的Neovim的安装步骤&#xff1a; 安装neovim Index of /pub/epelhttps://dl.fedoraproject.org/pub/epel/ yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm yum install -y neovim python3-neovim yum install -y …

【MySQL】不允许你不会全文本搜索

&#x1f3ac; 博客主页&#xff1a;博主链接 &#x1f3a5; 本文由 M malloc 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;LeetCode刷题集 &#x1f3c5; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0…

【ShenYu系列】ShenYu网关条件匹配的设计及原理分析

ShenYu网关中用到了很多有趣的设计&#xff0c;我对其中的条件匹配的实现尤其感兴趣&#xff0c;所以研究一下具体实现的原理。我这边用到的shenyu版本是2.6.0-SNAPSHOT。 应用入口 原理拆解 AbstractShenyuPlugin#execute&#xff0c;获取到SelectorData集合&#xff0c;进行…

Inkscape扩展脚本入门

Inkscape官网 https://inkscape.org/ 建议下载1.3版本 官方插件脚本文档 https://inkscape-extensions-guide.readthedocs.io/en/latest/index.html 但这个文档似乎和当前版本不符合&#xff0c;直接按照其内的方法写脚本会有问题 Inkscape插件加载目录 默认情况下&…

LVGL开发:配置模拟器学习LVGL V8.3

文章目录 模拟器配置常用控件学习基本知识WidgetEvents 输入设备ImagesScreen 参考 模拟器配置 LVGL支持多种IDE下配置模拟器&#xff1a; 在WINDOWS下面&#xff0c;大家最常使用的是VS2019&#xff0c;为了和大家保持一致&#xff0c;这里也使用VS2019进行配置。 首先&…

Matlab export_fig 输出高清图片和部分运行错误问题

Matlab export_fig 输出占空间较小的矢量高清图和部分运行错误问题 Matlab export_fig 的安装与运行错误export_fig 配置&#xff1a;安装后一直提示加载Ghostscript运行错误export_fig输出pdf的本质过程export_fig介绍几种生成图片的大小 Matlab export_fig 的安装与运行错误 …

mysql数据库备份与还原、索引、视图

一、备份与还原 /***************************样例表***************************/ CREATE DATABASE booksDB; use booksDB; CREATE TABLE books ( bk_id INT NOT NULL PRIMARY KEY, bk_title VARCHAR(50) NOT NULL, copyright YEAR NOT NULL …

Transaction事务使用了解

1.功能概述 ​ 在wiki的解释中&#xff0c;事务是一组单元化的操作&#xff0c;这组操作可以保证要么全部成功&#xff0c;要么全部失败&#xff08;只要有一个失败的操作&#xff0c;就会把其他已经成功的操作回滚&#xff09;。 ​ 这样的解释还是不够直观&#xff0c;看下…