pygame-ce
pygame-ce copied to clipboard
sprites now have limited support for Texture and Renderer
@rethanon was playing around with _sdl2.video and tried combining sprites and gpu rendering. Things went wrong, this is my attempt to add some basic intercompat between the two because it's already pretty compatible (at least at a minimal functioning level)
Sample code (provided by rethanon on discord)
import random
import time
import pygame
import pygame._sdl2 as sdl2
pygame.init()
WINDOW: pygame.Window = pygame.Window("Sprite Test", (800, 600))
RENDERER: sdl2.Renderer = sdl2.Renderer(WINDOW)
RENDERER.draw_color = "midnightblue"
running: bool = True
frame_start: float = time.perf_counter()
blocks = pygame.sprite.Group()
class Block(pygame.sprite.Sprite):
def __init__(self) -> None:
pygame.sprite.Sprite.__init__(self)
self.image: sdl2.Texture = sdl2.Texture.from_surface(
RENDERER, pygame.Surface((60, 60))
)
self.rect: pygame.FRect = pygame.FRect(
self.image.get_rect(
topleft=(
random.randint(0, 800 - self.image.width),
random.randint(0, 600 - self.image.height),
)
)
)
self.movement_speed_x: int = random.choice([-5, -4, -3, -2, -1, 1, 2, 3, 4, 5])
self.movement_speed_y: int = random.choice([-5, -4, -3, -2, -1, 1, 2, 3, 4, 5])
def update(self, delta_time: float) -> None:
self.rect.x += self.movement_speed_x * 60 * delta_time
self.rect.y += self.movement_speed_y * 60 * delta_time
self.rect.clamp_ip(pygame.Rect(0, 0, 800, 600))
if (self.rect.left == 0 and self.movement_speed_x < 0) or (
self.rect.right == 800 and self.movement_speed_x > 0
):
self.movement_speed_x *= -1
if (self.rect.top == 0 and self.movement_speed_y < 0) or (
self.rect.bottom == 600 and self.movement_speed_y > 0
):
self.movement_speed_y *= -1
for _ in range(20):
Block().add(blocks)
while running:
frame_end: float = time.perf_counter()
delta_time: float = frame_end - frame_start
frame_start = time.perf_counter()
for event in pygame.event.get():
if event.type == pygame.WINDOWCLOSE:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
RENDERER.clear()
blocks.update(delta_time)
blocks.draw(RENDERER)
RENDERER.present()
Just a minor nitpick but I'd like whitespace/formatting changes to be a separate PR, preferably with some way to keep it automated with changes to our precommit config
Same lol. My editor is configured to remove trailing whitespace on file save though, so I'd have to either change my editor config just for pygame-ce, or edit files in a different editor when I want to make a pull request. Alternatively, someone can put together a whitespace-fix PR pretty quickly and then those won't show as diffs anymore
Also, I have absolutely no idea why this pull is causing segfaults
import random
import sys
import time
import pygame
import pygame._sdl2 as sdl2
if "--cpu" in sys.argv:
USE_GPU = False
else:
USE_GPU = True
pygame.init()
WINDOW: pygame.Window = pygame.Window("Sprite Test", (800, 600))
if USE_GPU:
RENDERER: sdl2.Renderer = sdl2.Renderer(WINDOW)
RENDERER.draw_color = "midnightblue"
else:
screen = WINDOW.get_surface()
running: bool = True
frame_start: float = time.perf_counter()
blocks = pygame.sprite.Group()
alien = pygame.image.load("examples/data/alien1.png")
class Block(pygame.sprite.Sprite):
def __init__(self) -> None:
pygame.sprite.Sprite.__init__(self)
if USE_GPU:
self.image = sdl2.Texture.from_surface(RENDERER, alien)
else:
self.image = alien.copy()
self.rect: pygame.FRect = pygame.FRect(
self.image.get_rect(
topleft=(
random.randint(0, 800 - self.image.width),
random.randint(0, 600 - self.image.height),
)
)
)
self.movement_speed_x: int = random.choice([-5, -4, -3, -2, -1, 1, 2, 3, 4, 5])
self.movement_speed_y: int = random.choice([-5, -4, -3, -2, -1, 1, 2, 3, 4, 5])
def update(self, delta_time: float) -> None:
self.rect.x += self.movement_speed_x * 60 * delta_time
self.rect.y += self.movement_speed_y * 60 * delta_time
self.rect.clamp_ip(pygame.Rect(0, 0, 800, 600))
if (self.rect.left == 0 and self.movement_speed_x < 0) or (
self.rect.right == 800 and self.movement_speed_x > 0
):
self.movement_speed_x *= -1
if (self.rect.top == 0 and self.movement_speed_y < 0) or (
self.rect.bottom == 600 and self.movement_speed_y > 0
):
self.movement_speed_y *= -1
for _ in range(20):
Block().add(blocks)
while running:
frame_end: float = time.perf_counter()
delta_time: float = frame_end - frame_start
frame_start = time.perf_counter()
WINDOW.title = f"fps = {1 / delta_time}"
for event in pygame.event.get():
if event.type == pygame.WINDOWCLOSE:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if USE_GPU:
RENDERER.clear()
else:
screen.fill("midnightblue")
blocks.update(delta_time)
if USE_GPU:
blocks.draw(RENDERER)
RENDERER.present()
else:
blocks.draw(screen)
WINDOW.flip()
Updated test script that lets you run both cpu and gpu
Note that the stub changes to _SupportsSprite and Sprite will make sprite typing harder.
First, typing users will have to deal with an extra possible type when accessing image from Sprite.
Second, the mutable image attribute type was broadened, which may be incompatible for code that is checked for mutable override in subclasses (a check usually disabled by default, though).