Moving a circle randomly in PyQt5 on its own?

Viewed 253

I'm trying to create two circles, which are moving around randomly within an area and changing their color if they collide.

There are many examples of creating circles and moving them around by mouse dragging, but I didn't find anything, where the object has to move on its own.

This is, what I already have:

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QGraphicsEllipseItem
import sys, random

class Circle (QGraphicsEllipseItem):
    def __init__(self, x, y, r, condition):
        super().__init__(0,0,r,r)
        self.setPos(x,y)
        self.condition = condition

    def setColor(self):
        if self.condition == "changable":
            self.setBrush(Qt.blue)
        elif self.condition == "notChangable":
            self.setBrush(Qt.black)

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

        self.scene = QGraphicsScene()
        self.setScene(self.scene)
        self.setSceneRect(0, 0, 600, 600)

        self.circle1 = Circle(random.randint(0,600), random.randint(0,600), 20, "changable")
        self.circle2 = Circle(random.randint(0,600), random.randint(0,600), 20, "notChangable")
        self.circle1.setColor()
        self.circle2.setColor()
        self.scene.addItem(self.circle1)
        self.scene.addItem(self.circle2)

app = QApplication(sys.argv)

view = GraphicView()
view.show()
sys.exit(app.exec_())

The "changeable"-circle shall update its condition to "not changeable" if it collides with the "not changeable"-circle.

So, how can I make these circles move randomly within the area and let them change their condition?

1 Answers

To create a random but smooth movement then you must use a QVariantAnimation, and to check the collision of items then you must use the collidingItems() method but you must do it every time the item's position changes, and that can be done in the itemChange() method:

from PyQt5.QtCore import Qt, QPointF, QTimer, QVariantAnimation
from PyQt5.QtWidgets import (
    QApplication,
    QGraphicsItem,
    QGraphicsView,
    QGraphicsScene,
    QGraphicsEllipseItem,
)
import sys, random


class Circle(QGraphicsEllipseItem):
    def __init__(self, x, y, r):
        super().__init__(0, 0, r, r)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
        self.setPos(x, y)
        self.setBrush(Qt.black)

        self._animation = QVariantAnimation(duration=1000)
        self._animation.valueChanged.connect(self.setPos)
        self._animation.finished.connect(self.create_random_point)

    def create_random_point(self):
        pos = random.sample(range(0, 600), 2)
        self.move_to(*pos)

    def move_to(self, x, y):
        self._animation.setStartValue(self.pos())
        self._animation.setEndValue(QPointF(x, y))
        self._animation.start()

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemPositionHasChanged:
            self.setBrush(Qt.blue if self.collidingItems() else Qt.black)
        return super().itemChange(change, value)


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

        scene = QGraphicsScene(self)
        self.setScene(scene)
        self.setSceneRect(0, 0, 600, 600)

        for _ in range(10):
            pos = random.sample(range(0, 600), 2)
            circle = Circle(*pos, 20)
            circle.create_random_point()
            self.scene().addItem(circle)


app = QApplication(sys.argv)

view = GraphicView()
view.show()
sys.exit(app.exec_())
Related