This test runs a pygame‑ce simulation inside a separate thread while a PyQt6 window displays a real‑time performance chart. The pygame engine creates multiple moving sprites, updates their positions every frame, and performs continuous collision detection between all sprites. During each frame, the engine measures the current FPS (frames per second) and counts how many sprite‑to‑sprite collisions occurred.
The PyQt6 interface collects these values and plots them live using PyQtGraph. The yellow curve represents the FPS over time, showing how well the pygame‑ce engine performs under load, while the red curve shows the number of collisions detected each frame. Together, the two curves let you visually evaluate both rendering performance and collision‑handling complexity as the simulation runs.
The source code is created with copilot artificial intelligence, tested and works very well.
import sys
import time
import threading
import pygame
from pygame.sprite import Sprite, Group
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout
from PyQt6.QtCore import QTimer
import pyqtgraph as pg
# -------------------------------
# SPRITE PYGAME
# -------------------------------
class TestSprite(Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((30, 30))
self.image.fill((255, 255, 0))
self.rect = self.image.get_rect(topleft=(x, y))
self.vx = 3
self.vy = 3
def update(self):
self.rect.x += self.vx
self.rect.y += self.vy
if self.rect.left < 0 or self.rect.right > 800:
self.vx *= -1
if self.rect.top < 0 or self.rect.bottom > 600:
self.vy *= -1
# -------------------------------
# THREAD PYGAME
# -------------------------------
class PygameThread(threading.Thread):
def __init__(self):
super().__init__()
self.running = True
self.fps_value = 0
self.collision_count = 0
def run(self):
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
sprites = Group()
for i in range(50):
sprites.add(TestSprite(i * 15, i * 10))
while self.running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
sprites.update()
# collision detection
collisions = pygame.sprite.groupcollide(sprites, sprites, False, False)
self.collision_count = sum(len(v) for v in collisions.values())
screen.fill((0, 0, 0))
sprites.draw(screen)
pygame.display.flip()
self.fps_value = clock.get_fps()
clock.tick(0)
pygame.quit()
# -------------------------------
# PYQT6 UI + CHART
# -------------------------------
class FPSWindow(QWidget):
def __init__(self, pg_thread):
super().__init__()
self.pg_thread = pg_thread
self.setWindowTitle("PyQt6 + pygame-ce FPS Chart + Collision Test")
layout = QVBoxLayout(self)
self.plot = pg.PlotWidget()
self.plot.setYRange(0, 200)
self.plot.showGrid(x=True, y=True)
layout.addWidget(self.plot)
self.data_fps = []
self.data_collisions = []
self.curve_fps = self.plot.plot(pen='y')
self.curve_col = self.plot.plot(pen='r')
self.timer = QTimer()
self.timer.timeout.connect(self.update_chart)
self.timer.start(50)
def update_chart(self):
self.data_fps.append(self.pg_thread.fps_value)
self.data_collisions.append(self.pg_thread.collision_count)
if len(self.data_fps) > 300:
self.data_fps.pop(0)
self.data_collisions.pop(0)
self.curve_fps.setData(self.data_fps)
self.curve_col.setData(self.data_collisions)
# -------------------------------
# MAIN
# -------------------------------
if __name__ == "__main__":
pg_thread = PygameThread()
pg_thread.start()
app = QApplication(sys.argv)
win = FPSWindow(pg_thread)
win.resize(900, 500)
win.show()
app.exec()
pg_thread.running = False
pg_thread.join()
