import json import pygame from pygame import transform, gfxdraw, Vector2, Surface from math import sin, cos, pi from time import time, sleep from random import random class Star: def __init__(self, sid: str, x: int, y: int, alpha: float, rot: float, scale: float, offset: float, image: pygame.Surface): self.sid = sid self.x = x self.y = y self.rot = rot self.alpha = alpha self.scale = scale self.offset = offset self.image = image class Screen: def __init__(self, stars: list[Star], background: Surface | None) -> None: if not pygame.get_init(): pygame.init() self.screen = pygame.display.set_mode((1920, 1080)) self.clock = pygame.time.Clock() self.stars = stars self.last = time() self.brightness = 1.0 self.active_scene = 0 self.last_scene = 0 self.scene_time: float = 0 self.background = background def update(self, scene_data): self.screen.fill((0, 0, 0)) now = time() delta = now - self.last self.last = now self.scene_time += delta weight = sin(min(self.scene_time, pi/2)) ** 2 def update_star_scene(star, old, new, weight): star.x = weight*new[star.sid]['x'] + (1-weight)*old[star.sid]['x'] star.y = weight*new[star.sid]['y'] + (1-weight)*old[star.sid]['y'] star.rot = weight*new[star.sid]['rot'] + (1-weight)*old[star.sid]['rot'] star.scale = weight*new[star.sid]['scale'] + (1-weight)*old[star.sid]['scale'] # first draw the background, if any if self.background: ratio_x = self.screen.get_width() / self.background.get_width() ratio_y = self.screen.get_height() / self.background.get_height() scaled_background = transform.rotozoom(self.background, 0, max(ratio_x, ratio_y)) bg_pos = ( (self.screen.get_width() - scaled_background.get_width()) / 2, (self.screen.get_height() - scaled_background.get_height()) / 2 ) self.screen.blit(scaled_background, bg_pos) # draw all the star objects for star in self.stars: update_star_scene(star, scene_data[self.last_scene], scene_data[self.active_scene], weight) star.alpha += star.rot * delta scaled = transform.rotozoom(star.image, star.alpha, star.scale) (w, h) = scaled.get_size() pos = (star.x*self.screen.get_width() - w/2, star.y*self.screen.get_height() - h/2) self.screen.blit(scaled, pos) overlay = pygame.surface.Surface((1920, 1080), depth=32) overlay.set_alpha(int(255 * (1 - self.brightness))) self.screen.blit(overlay, (0, 0)) pygame.display.flip() self.clock.tick(60) def close(self): pygame.quit()