pybeamshow/effects/doublespot.py

154 lines
4.8 KiB
Python
Raw Normal View History

2023-02-17 02:06:45 +01:00
from typing import Any, List, Tuple
import pygame as pg
2023-02-22 22:55:11 +01:00
from effects.effect import Effect
2023-02-24 18:21:21 +01:00
from util import XYCoord
from util.color import Colors, ColorGenerator
2023-02-17 02:06:45 +01:00
import random
2023-02-23 02:10:50 +01:00
from typing import Generator
2023-02-17 02:06:45 +01:00
2023-02-18 23:17:03 +01:00
def fade_statemachine(
fade_in: int, hold: int, fade_out: int
) -> Generator[Tuple[int, bool, bool], None, None]:
2023-02-17 02:06:45 +01:00
for t in range(fade_in):
yield 255 * t // fade_in, False, False
for t in range(hold):
yield 255, False, False
for t in range(fade_out):
yield 255 * (fade_out - t) // fade_out, True, False
yield 0, True, True
class Spot(pg.sprite.Sprite):
def __init__(
self,
color: pg.Color,
2023-02-24 18:21:21 +01:00
position: XYCoord,
2023-02-17 02:06:45 +01:00
radius: int,
fade_in: int,
hold: int,
fade_out: int,
) -> None:
super().__init__()
self.rect = pg.Rect(
position[0] - radius, position[1] - radius, radius * 2, radius * 2
)
self.image = pg.Surface(self.rect.size)
self.image.set_colorkey(Colors.Black)
self.image.fill(Colors.Black)
pg.draw.ellipse(
self.image,
color,
((0, 0), self.rect.size),
)
self.start_next = False
self.finished = False
self.state = fade_statemachine(fade_in, hold, fade_out)
def update(self) -> None:
if not self.finished:
alpha, self.start_next, self.finished = next(self.state)
self.image.set_alpha(alpha)
def draw(self, dest: pg.Surface) -> None:
dest.blit(self.image, self.rect)
class DoubleSpot(Effect):
def __init__(
self,
bounds: pg.Rect,
2023-02-24 18:21:21 +01:00
color: ColorGenerator,
2023-02-17 02:06:45 +01:00
radius: int = 200,
hold: int = 60 * 1,
fade_out: bool = False,
fade_in: bool = False,
2023-02-19 02:01:28 +01:00
beat_adapt: bool = False,
2023-02-17 02:06:45 +01:00
*groups: pg.sprite.Group
) -> None:
self.color = color
self.radius: int = radius
self.fade_in_time: int = hold // 4 if fade_in else 0
self.fade_out_time: int = hold // 4 if fade_out else 0
self.hold_time: int = hold - (self.fade_in_time + self.fade_out_time)
2023-02-19 02:01:28 +01:00
self.beat_adapt: bool = beat_adapt
2023-02-17 02:06:45 +01:00
self.spots: List[Spot] = []
self.randrange = (
(bounds.width - 2 * self.radius) // (self.radius * 2),
(bounds.height - 2 * self.radius) // (self.radius * 2),
)
image = pg.Surface(size=bounds.size)
image.set_colorkey(Colors.Black)
2023-02-18 23:17:03 +01:00
super().__init__(image, bounds, *groups)
2023-02-17 02:06:45 +01:00
2023-02-19 02:01:28 +01:00
self.update(is_beat=False, frames_per_beat=0.0)
2023-02-17 02:06:45 +01:00
def add_spot(self, spot_color):
position = (
random.randint(0, self.randrange[0]) * self.radius * 2 + self.radius,
random.randint(0, self.randrange[1]) * self.radius * 2 + self.radius,
)
2023-02-18 23:17:03 +01:00
while any(
(
(s.rect.centerx == position[0] and s.rect.centery == position[1])
for s in self.spots
)
):
2023-02-17 02:06:45 +01:00
position = (
random.randint(0, self.randrange[0]) * self.radius * 2 + self.radius,
random.randint(0, self.randrange[1]) * self.radius * 2 + self.radius,
)
self.spots.append(
Spot(
color=spot_color,
position=position,
radius=self.radius,
fade_in=self.fade_in_time,
hold=self.hold_time,
fade_out=self.fade_out_time,
)
)
def update(self, *args: Any, **kwargs: Any) -> None:
self.image.fill(Colors.Black)
2023-02-19 02:01:28 +01:00
if self.beat_adapt and kwargs["frames_per_beat"]:
hold = kwargs["frames_per_beat"] - 2
self.fade_in_time = int(hold // 4 if self.fade_in_time else 0)
self.fade_out_time = int(hold // 4 if self.fade_out_time else 0)
self.hold_time = int(hold - self.fade_in_time)
if not self.beat_adapt:
if len(self.spots) == 0 or (
self.fade_in_time != 0
and self.spots[0].start_next
and len(self.spots) == 2
):
spot_color = (
2023-02-24 18:21:21 +01:00
next(self.color),
2023-02-19 02:01:28 +01:00
)
self.add_spot(spot_color)
self.add_spot(spot_color)
elif kwargs["is_beat"]:
2023-02-17 02:06:45 +01:00
spot_color = (
2023-02-24 18:21:21 +01:00
next(self.color),
2023-02-17 02:06:45 +01:00
)
self.add_spot(spot_color)
self.add_spot(spot_color)
for spot in self.spots:
if not spot.finished:
spot.update()
spot.draw(self.image)
if self.spots:
first_spot = self.spots[0]
while self.spots and first_spot.finished:
first_spot = self.spots.pop(0)
del first_spot
if self.spots:
first_spot = self.spots[0]