Skip to content
Advertisement

How to Detect collisions in PyQt5

Iam making a simple game using PyQt, but i don’t know how i can detect the collisions between enemy and bullets, there is a C++ implementation, but i dont know how i can do that in PyQt. and it should be done in Bullet.py file. these are the files.

Window.py

from PyQt6.QtWidgets import QGraphicsScene,QApplication, QGraphicsView, QGraphicsItem
from PyQt6.QtCore import Qt, QTimer
import sys
from Player import Player
from Enemy import Enemy


class Window(QGraphicsView):
    def __init__(self):
        super().__init__()

    self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
    self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)

    self.setFixedSize(800, 600)
    self.create_scene()

    self.show()




def create_scene(self):
    self.scene = QGraphicsScene()

    #create an item to put in the scene
    player = Player()

    #make rect focusable
    player.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsFocusable)
    player.setFocus()


    #by default QGraphicsRectItem has 0 length and width
    player.setRect(0,0, 100,100)

    #add item to the scene
    self.scene.addItem(player)

    #set size of the scene
    self.scene.setSceneRect(0, 0, 800, 600)

    #set the player at the botoom
    player.setPos(self.width() / 2, self.height() - player.rect().height())
     
     # create our score
    score = Score()
    self.scene.addItem(score)

    self.setScene(self.scene)

    self.timer = QTimer()
    self.timer.timeout.connect(self.spawn)
    self.timer.start(2000)


def spawn(self):
    enemy = Enemy()
    self.scene.addItem(enemy)


App = QApplication(sys.argv)
window = Window() 
sys.exit(App.exec())

Player.py

from PyQt6.QtWidgets import QGraphicsRectItem
from PyQt6.QtGui import QKeyEvent
from PyQt6.QtCore import Qt
from Bullet import MyBullet




class Player(QGraphicsRectItem):
    def __init__(self):
       super().__init__()



def keyPressEvent(self, event: QKeyEvent):
    if (event.key() == Qt.Key.Key_Left):

        if self.pos().x() > 0:
            self.setPos(self.x() - 10, self.y())

    elif (event.key() == Qt.Key.Key_Right):
        if (self.pos().x() + 100 < 800):
            self.setPos(self.x() + 10, self.y())


    elif (event.key() == Qt.Key.Key_Space):
        mybullet = MyBullet()
        mybullet.setPos(self.x(), self.y())
        self.scene().addItem(mybullet)

Enemy.py

from PyQt6.QtWidgets import QGraphicsRectItem
from random import randint
from PyQt6.QtCore import QTimer


class Enemy(QGraphicsRectItem):
    def __init__(self):
        super().__init__()

    random_number = randint(10,1000) % 700
    self.setPos(random_number , 0)


    self.setRect(0,0,100,100)

    self.timer = QTimer()
    self.timer.timeout.connect(self.move)
    self.timer.start(50)




def move(self):
    #move enemy to down
    self.setPos(self.x(), self.y()+5)

    if self.pos().y() + self.rect().height() < 0:
        self.scene().removeItem(self)
        print("Bullet deleted")

Bullet.py

from PyQt6.QtWidgets import QGraphicsRectItem, QGraphicsItem
from PyQt6.QtCore import QTimer
from Enemy import Enemy




class MyBullet(QGraphicsRectItem):
    def __init__(self):
        super().__init__()
    score = Score() 

    self.setRect(0,0,10,50)

    self.timer = QTimer()
    self.timer.timeout.connect(self.move)
    self.timer.start(50)


def move(self):
    
    #This is the place for the collision 
    colliding = self.collidingItems()
    for item in colliding:
        if isinstance(item, Enemy):
            #increase the score
            score.increase()
            self.scene().removeItem(item)
            self.scene().removeItem(self)


    self.setPos(self.x(), self.y() - 10)

    if self.pos().y() + self.rect().height() < 0:
        self.scene().removeItem(self)
        print("Bullet deleted")
       

Score.py from PyQt6.QtWidgets import QGraphicsTextItem from PyQt6.QtCore import Qt

from PyQt6.QtGui import QFont

class Score(QGraphicsTextItem):

    def __init__(self):
       super().__init__()

    self.score = 0

    #draw the text
    self.setPlainText("Score : " + str(self.score))
    self.setDefaultTextColor(Qt.GlobalColor.red)
    self.setFont(QFont("Sanserif", 18))



def increase(self):
    self.score += 1
    self.setPlainText(str(self.score))
    print(self.score)

This is the C++ code, i want similiar of that for Python.

QList<QGraphicsItem *> colliding_items = collidingItems();
for (int i = 0, n = colliding_items.size(); i < n; ++i) {
    if (typeid(*(colliding_items[i])) == typeid(Enemy)) {
        scene->removeItem(colliding_items[i]);
        scene->removeItem(this);

    }
}

Advertisement

Answer

QGraphicsItem has collidingItems method that use QGraphicsItem.boundingRect() to detect collisions. It is implemented for QGraphicsRectItem. So you only need to call it and iterate over items.

class MyBullet(QGraphicsRectItem):
    
    def move(self):
        colliding = self.collidingItems()
        for item in colliding:
            if isinstance(item, Enemy):
                self.scene().removeItem(item)
                self.scene().removeItem(self)
                return
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement