110 lines
4.0 KiB
Python
110 lines
4.0 KiB
Python
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
|
|
|
|
INTERPOLATION = {
|
|
'sin2': lambda x: sin(x) ** 2,
|
|
'sin': lambda x: sin(x),
|
|
'cos': lambda x: 1 - cos(x),
|
|
'lin': lambda x: x
|
|
}
|
|
|
|
FADE = {
|
|
(True, True): lambda x: sin(x) ** 2, # fade both
|
|
(True, False): lambda x: 1 - cos(x), # fade in
|
|
(False, True): lambda x: sin(x), # fade out
|
|
(False, False): lambda x: x / (pi/2) # linear
|
|
}
|
|
|
|
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, framerate: float = 30) -> None:
|
|
if not pygame.get_init():
|
|
pygame.init()
|
|
self.screen = pygame.display.set_mode((1920, 1080), display=1, flags=pygame.FULLSCREEN | pygame.DOUBLEBUF | pygame.WINDOWTAKEFOCUS)
|
|
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.framerate: float = framerate
|
|
self.overlay = pygame.surface.Surface(self.screen.get_size(), depth=32)
|
|
if background:
|
|
ratio_x = self.screen.get_width() / background.get_width()
|
|
ratio_y = self.screen.get_height() / background.get_height()
|
|
scaled_background = transform.rotozoom(background, 0, max(ratio_x, ratio_y))
|
|
|
|
self.bg_pos = (
|
|
(self.screen.get_width() - scaled_background.get_width()) / 2,
|
|
(self.screen.get_height() - scaled_background.get_height()) / 2
|
|
)
|
|
self.background = scaled_background
|
|
else:
|
|
self.background = None
|
|
self.bg_pos = None
|
|
|
|
|
|
|
|
def update(self, scene_data):
|
|
if not self.background:
|
|
self.screen.fill((0, 0, 0))
|
|
now = time()
|
|
delta = now - self.last
|
|
self.last = now
|
|
|
|
self.scene_time += delta
|
|
fade_in = scene_data[self.active_scene]['transition']['fade_in']
|
|
fade_out = scene_data[self.active_scene]['transition']['fade_out']
|
|
t = FADE[(fade_in, fade_out)](min(self.scene_time / scene_data[self.active_scene]['transition']['t'], 1) * pi/2) * pi/2
|
|
weight_x = INTERPOLATION[scene_data[self.active_scene]['transition']['x']](t)
|
|
weight_y = INTERPOLATION[scene_data[self.active_scene]['transition']['y']](t)
|
|
weight = INTERPOLATION['sin2'](t)
|
|
|
|
def update_star_scene(star, old, new):
|
|
star.x = weight_x*new[star.sid]['x'] + (1-weight_x)*old[star.sid]['x']
|
|
star.y = weight_y*new[star.sid]['y'] + (1-weight_y)*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:
|
|
self.screen.blit(self.background, self.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])
|
|
star.alpha += star.rot * delta
|
|
computed_scale = star.scale * (self.screen.get_width() / star.image.get_width() / 100)
|
|
scaled = transform.rotozoom(star.image, star.alpha, computed_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)
|
|
|
|
|
|
self.overlay.set_alpha(int(255 * (1 - self.brightness)))
|
|
self.screen.blit(self.overlay, (0, 0))
|
|
|
|
pygame.display.flip()
|
|
self.clock.tick(self.framerate)
|
|
|
|
def close(self):
|
|
pygame.quit() |