Graphical interface development based on PyQt5-Brickbreaker

0. Preface

This article uses PyQt5 to implement a brick breaking game

insert image description here

OS: Windows 10 Professional

Development environment: Pycahrm Community 2022.3

Python interpreter version: Python3.8

Third-party library: PyQt5

1. Brick class definition

In the constructor __init__, the Brick class accepts two parameters x and y, which represent the position of the brick when it is initialized. Initialize the base class of QGraphicsRectItem by calling super().__init__, and pass in parameters 0, 0, 40, 20 to set the initial size of the brick. Then use the setPos method to set the brick's position to the given x and y.

Next, use the setBrush method to set the color of the bricks to red. QColor(150, 0, 0) represents red, where 150 represents the brightness of the red channel and 0 represents 0 brightness of the green and blue channels.

Use the setFlag method to set the QGraphicsItem.ItemIsSelectable flag, indicating that the brick can be selected.

The destroy method is used to remove bricks. In this method, use self.scene.removeItem(self) to remove the brick from the scene.

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. Definition of bezel class

This code defines a class called Paddle, which inherits from QGraphicsRectItem and is used to represent the baffle in the brick breaking game.

In the function __init__, the Paddle class uses the super().__init__ method to initialize the base class of QGraphicsRectItem, setting the initial size of the bezel to 80 pixels wide and 10 pixels high. Then use the setPos method to set the position of the bezel to (360, 540).

Next, use the setBrush() method to set the color of the bezel to blue. QColor(0, 0, 150) means blue, where 0 means the red and green channels have a brightness of 0, and 150 means the blue channel has a brightness of 150.

Use the setFlag method to set the QGraphicsItem.ItemIsMovable flag, indicating that the bezel can be moved by dragging the mouse.

The moveLeft method is used to move the bezel to the left. In this method, first judge whether the x coordinate of the current baffle is greater than or equal to 10, so as to ensure that the baffle will not exceed the left boundary. If the condition is met, use the setPos method to subtract 20 from the x coordinate of the bezel to move to the left.

The moveRight method is used to move the bezel to the right. In this method, it is first judged whether the x coordinate of the current barrier is less than or equal to 710, so as to ensure that the barrier does not exceed the right boundary. If the condition is met, use the setPos method to add 20 to the x coordinate of the bezel to move to the right.

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. Collision detection

Define a class named Ball, which inherits from QGraphicsEllipseItem and is used to represent the ball in the Arkanoid game.

In the constructor __init__, the Ball class uses the super().__init__ method to initialize the base class of QGraphicsEllipseItem, setting the initial size of the ball to 20 pixels in diameter. Then use the setPos method to set the position of the ball to (390, 520).

Next, use the setBrush method to set the color of the ball to green. QColor(0, 150, 0) represents green, where 0 means the red and blue channels have a brightness of 0, and 150 means the green channel has a brightness of 150.

The Ball class also defines two variables, dx and dy, which represent the speed of the ball on the x-axis and y-axis respectively. In the constructor, dx and dy are initialized to -5, which means that the speed of the ball in the horizontal and vertical directions is -5.

The score variable is used to record the game score, and the initial value is 0.

The advance method is used to update the position and state of the ball when each frame is updated. First judge whether it is an update phase, if not, return directly. Then by changing the position of the ball, use the setPos method to increase the x coordinate of the ball by dx and the y coordinate by dy to realize the movement of the ball.

Next, perform collision detection to determine whether the ball collides with the boundary, baffle or brick, and perform corresponding processing according to the collision result.

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. Ball and game initialization

This code defines a class called MainScene, which is based on a subclass of QtWidgets.QGraphicsScene. This class is used to create a game scene, and includes functions such as initializing the size of the scene, adding baffles, adding balls, initializing the position of bricks and scoring panels.

In the initialization method __init__, the size of the scene is set to 800x600, and the global variables bricks, paddle, ball and score are declared. Then create a Paddle object and add it to the scene, then create a Ball object and add it to the scene.

Next, use a loop to initialize the position of the bricks, create 20 Brick objects, add them to the scene according to the position, and store these brick objects in the bricks list.

At the end of the code, a QLabel object score is created to display the score, its position and font style are set, and then it is added to the scene. At the same time, a keyPressEvent method is defined to capture keyboard key events. When the left arrow key is pressed, the moveLeft method of the paddle object is called, and when the right arrow key is pressed, the moveRight method of the paddle object is called.

In the advance method, use the advance method of the parent class to update the scene state, and update the displayed score text according to the current score of the ball.

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. Complete code

All it takes is this one file to run:
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. Run the effect demonstration

Since I used the random library to generate the brick position, each scene is different:
insert image description here

insert image description here

7. Pyinstaller compiles exe program

insert image description here
Enter this:

Pyinstaller -F main.py

insert image description here
Wait for the compilation to complete

You can find main.exe in ./dist
insert image description here
and double-click it to enter the brick breaking game

PyQt5

Graphical interface development based on PyQt5 - weather application

Graphical interface development based on PyQt5 - self-made MQTT client

Graphical interface development based on PyQt5 - Windows memory resource monitoring assistant [compiled exe tutorial attached]

Graphical interface development based on PyQt5 - simulated hospital management system

Graphical interface development based on PyQt5 - self-made ssh tool

Graphical interface development based on PyQt5 - PyQt example_calculator

Graphical interface development based on PyQt5 - PyQt example Develop Paper

Graphical interface development based on PyQt5 - self-made Redis graphical client (source code attached at the end of the article)

Graphical interface development based on PyQt5 - stack animation demonstration

Graphical interface development based on PyQt5 - queue animation demonstration

Guess you like

Origin blog.csdn.net/qq_53381910/article/details/131730873