Pages

vineri, 10 aprilie 2026

PyGame : particles with the pygame and pyqt6 !

Today, I test one python script with pygame and pyqt6. The python script use classes and show particles. See the result:
These are python and pygame-ce, but the source code use pygame.
Python 3.13.0 (tags/v3.13.0:60403a5, Oct  7 2024, 09:38:07) [MSC v.1941 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pygame
pygame-ce 2.5.7 (SDL 2.32.10, Python 3.13.0)
>>> print(pygame.version.ver)
2.5.7
>>> print(pygame.version.SDL)
2.32.10
This is the source code:
import sys
import random
import pygame
from pygame import Vector2
from PyQt6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout,
    QSlider, QLabel, QSizePolicy
)
from PyQt6.QtCore import Qt, QTimer
from PyQt6.QtGui import QImage, QPainter

class Particle:
    def __init__(self, pos, vel, color):
        self.pos = Vector2(pos)
        self.vel = Vector2(vel)
        self.color = color
        self.life = 255

    def update(self, gravity):
        self.vel.y += gravity
        self.pos += self.vel
        self.life -= 2

    def draw(self, surf):
        if self.life > 0:
            pygame.draw.circle(
                surf,
                self.color,
                (int(self.pos.x), int(self.pos.y)),
                4
            )

class PygameWidget(QWidget):
    def __init__(self):
        super().__init__()

        pygame.init()
        pygame.display.init()

        self.w, self.h = 900, 600
        self.surface = pygame.Surface((self.w, self.h))

        self.particles = []
        self.spawn_rate = 5
        self.gravity = 0.1

        self.setSizePolicy(
            QSizePolicy.Policy.Expanding,
            QSizePolicy.Policy.Expanding
        )

        self.timer = QTimer()
        self.timer.timeout.connect(self.game_loop)
        self.timer.start(16)  # ~60 FPS

    def spawn_particles(self):
        for _ in range(self.spawn_rate):
            pos = (self.w // 2, self.h // 2)
            vel = (random.uniform(-2, 2), random.uniform(-2, 2))
            color = (255, random.randint(100, 255), 0)
            self.particles.append(Particle(pos, vel, color))

    def game_loop(self):
        self.surface.fill((20, 20, 20))

        self.spawn_particles()

        alive = []
        for p in self.particles:
            p.update(self.gravity)
            p.draw(self.surface)
            if p.life > 0:
                alive.append(p)

        self.particles = alive

        self.update()

    def paintEvent(self, event):
        data = pygame.image.tobytes(self.surface, "RGB")
        img = QImage(
            data,
            self.w,
            self.h,
            self.w * 3,
            QImage.Format.Format_RGB888
        )

        painter = QPainter(self)
        painter.drawImage(0, 0, img)
        painter.end()

    def resizeEvent(self, event):
        self.w = self.width()
        self.h = self.height()
        self.surface = pygame.Surface((self.w, self.h))

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("PyQt6 + pygame Particle System")

        main_layout = QVBoxLayout()

        # widget-ul pygame – ocupă tot spațiul
        self.pg_widget = PygameWidget()
        main_layout.addWidget(self.pg_widget, stretch=1)

        # panou de controale jos
        control_panel = QVBoxLayout()

        # ----- slider spawn rate -----
        spawn_layout = QHBoxLayout()
        spawn_label = QLabel("Spawn:")
        self.spawn_value = QLabel("5")

        spawn_slider = QSlider(Qt.Orientation.Horizontal)
        spawn_slider.setRange(1, 50)
        spawn_slider.setValue(5)
        spawn_slider.valueChanged.connect(self.update_spawn_rate)

        spawn_layout.addWidget(spawn_label)
        spawn_layout.addWidget(spawn_slider)
        spawn_layout.addWidget(self.spawn_value)

        # ----- slider gravity -----
        gravity_layout = QHBoxLayout()
        gravity_label = QLabel("Gravity:")
        self.gravity_value = QLabel("0.10")

        gravity_slider = QSlider(Qt.Orientation.Horizontal)
        gravity_slider.setRange(0, 50)
        gravity_slider.setValue(10)
        gravity_slider.valueChanged.connect(self.update_gravity)

        gravity_layout.addWidget(gravity_label)
        gravity_layout.addWidget(gravity_slider)
        gravity_layout.addWidget(self.gravity_value)

        control_panel.addLayout(spawn_layout)
        control_panel.addLayout(gravity_layout)

        main_layout.addLayout(control_panel)

        self.setLayout(main_layout)

    def update_spawn_rate(self, v):
        self.pg_widget.spawn_rate = v
        self.spawn_value.setText(str(v))

    def update_gravity(self, v):
        g = v / 100.0
        self.pg_widget.gravity = g
        self.gravity_value.setText(f"{g:.2f}")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MainWindow()
    w.resize(1000, 800)
    w.show()
    sys.exit(app.exec())

luni, 6 aprilie 2026

PyGame-CE : First test example with pygame-ce-2.5.7

The biggest technical difference in version 2.5.7 is the expanded use of SIMD (Single Instruction, Multiple Data)
It utilizes modern CPU instructions like AVX2 (Intel/AMD) and NEON (ARM/Apple Silicon).
Pixel-level operations—such as blending, alpha-compositing, and surface scaling 30% to 100% faster than the original Pygame. If you are doing real-time lighting or heavy particle effects
Let's install with:
python -m pip install pygame-ce
WARNING: Ignoring invalid distribution ~adquery-ocp (C:\Python313_64bit\Lib\site-packages)
Collecting pygame-ce
  Downloading pygame_ce-2.5.7-cp313-cp313-win_amd64.whl.metadata (11 kB)
Downloading pygame_ce-2.5.7-cp313-cp313-win_amd64.whl (10.4 MB)
   ---------------------------------------- 10.4/10.4 MB 2.8 MB/s  0:00:03
WARNING: Ignoring invalid distribution ~adquery-ocp (C:\Python313_64bit\Lib\site-packages)
Installing collected packages: pygame-ce
WARNING: Ignoring invalid distribution ~adquery-ocp (C:\Python313_64bit\Lib\site-packages)
Successfully installed pygame-ce-2.5.7
python
Python 3.13.0 (tags/v3.13.0:60403a5, Oct  7 2024, 09:38:07) [MSC v.1941 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pygame
pygame-ce 2.5.7 (SDL 2.32.10, Python 3.13.0)
>>> print(pygame.version.ver)      # Should be 2.5.7
2.5.7
>>> print(pygame.version.vernum)   # Should show the CE suffix
2.5.7
Comparison Summary: Pygame-CE 2.5.7 vs. Legacy Pygame
Feature Pygame-CE 2.5.7 Legacy Pygame
Rendering Engine Highly optimized C-code with SIMD Basic SDL2 wrappers
OS Integration Full (System notifications, Dark Mode) Minimal
Updates Monthly (Active community) Yearly or less (Stagnant)
Math & Rects Modernized, faster collision logic Older, slower C implementation
Multi-threading Ready for Python 3.13+ "Free-thread" Limited by the GIL
Next python script demonstrates a real-time bridge between a graphical user interface and the operating system's memory by utilizing the Pygame-CE scrap module to exchange text data with the system clipboard via keyboard inputs.
import pygame

# 1. Initialize Pygame
pygame.init()

# 2. Create the window (CRITICAL: Scrap needs a window to talk to the OS)
screen = pygame.display.set_mode((600, 400))
pygame.display.set_caption(f"Pygame-CE 2.5.7 Scrap Fix")

# 3. Initialize scrap safely
try:
    pygame.scrap.init()
except Exception:
    # Some builds initialize this automatically with display.set_mode
    pass

font = pygame.font.SysFont("Arial", 22)
clipboard_text = "Press 'V' to paste"
status_message = "Found: pygame.scrap.get_text"

running = True
while running:
    screen.fill((30, 30, 30))

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        
        if event.type == pygame.KEYDOWN:
            # COPY logic using scrap.put_text
            if event.key == pygame.K_c:
                msg = "Hello from Pygame-CE 2.5.7 Scrap!"
                try:
                    # Modern CE method for text
                    pygame.scrap.put_text(msg)
                    status_message = "Copied via scrap.put_text!"
                except AttributeError:
                    # Fallback for some 2.5.7 sub-builds
                    pygame.scrap.put(pygame.SCRAP_TEXT, msg.encode("utf-8"))
                    status_message = "Copied via scrap.put (fallback)!"
            
            # PASTE logic using scrap.get_text
            if event.key == pygame.K_v:
                # Based on your discovery, this IS the method
                txt = pygame.scrap.get_text()
                if txt:
                    # scrap.get_text() usually returns a string directly
                    clipboard_text = txt.replace('\x00', '') # Clean null bytes
                    status_message = "Pasted successfully!"
                else:
                    status_message = "Clipboard is empty."

    # Rendering
    surf_clip = font.render(f"Content: {clipboard_text}", True, (255, 255, 255))
    surf_stat = font.render(status_message, True, (0, 255, 0))
    screen.blit(surf_clip, (50, 150))
    screen.blit(surf_stat, (50, 250))
    
    pygame.display.flip()

pygame.quit()