pybeamshow/effects/moonflower.py
2023-02-23 00:19:20 +01:00

101 lines
3.1 KiB
Python

from typing import Any, Optional, Tuple
import pygame as pg
from effects.effect import MovingEffect
from util.color import Colors
import math
from typing import Union, Generator
from util.transform import PositionGenerator
def calc_radii(size, f):
r_c = size / (5 * f + 2)
r_a = size / 2 - r_c
return r_c, r_a
class Moonflower(MovingEffect):
def __init__(
self,
bounds: pg.Rect,
colors: Tuple[
Union[pg.Color, Generator[pg.Color, None, None]],
Union[pg.Color, Generator[pg.Color, None, None]],
],
mover: Optional[PositionGenerator] = None,
beat_color: bool = False,
size: int = 100,
rot_speed: float = 5,
outer: int = 5,
*groups: pg.sprite.Group
) -> None:
self.rot_speed = rot_speed
self.rotation = 0.0
self.colors = colors
self.beat_color = beat_color
self.o_count = outer
self.o_f = 1 / math.sin(math.pi / self.o_count)
self.spot_radius, self.o_radius = calc_radii(size, self.o_f)
self.i_radius = (self.o_radius - self.spot_radius) * 0.5
image = pg.Surface((size, size))
image.fill(Colors.Black)
image.set_colorkey(Colors.Black)
super().__init__(
image,
pg.Rect(
bounds.centerx - size / 2,
bounds.centery - size / 2,
size,
size,
),
mover,
*groups,
)
self.bounds = bounds
# self.bouncer = transform_bounce(
# bounds=bounds, velocity=velocity, x_factor=x_factor, y_factor=y_factor, on_beat_random_phase=True
# )
next(self.mover)
self.o_color = (
self.colors[0]
if isinstance(self.colors[0], pg.Color)
else next(self.colors[0])
)
self.i_color = (
self.colors[1]
if isinstance(self.colors[1], pg.Color)
else next(self.colors[1])
)
self.update(is_beat=False)
def update(self, *args: Any, **kwargs: Any) -> None:
self.rect.center = self.mover.send((self.rect.size, kwargs["is_beat"]))
self.image.fill(Colors.Black)
if not self.beat_color or kwargs["is_beat"]:
if isinstance(self.colors[0], Generator):
self.o_color = next(self.colors[0])
if isinstance(self.colors[1], Generator):
self.i_color = next(self.colors[1])
for phi in range(0, 360, 360 // self.o_count):
rads = math.pi * (phi + self.rotation) / 180
pos_x = self.rect.width // 2 + self.o_radius * math.cos(rads)
pos_y = self.rect.height // 2 + self.o_radius * math.sin(rads)
pg.draw.circle(
self.image,
self.o_color,
(pos_x, pos_y),
self.spot_radius,
)
pg.draw.circle(
self.image,
self.i_color,
self.image.get_rect().center,
self.i_radius,
)
self.rotation += self.rot_speed