pybeamshow/effects/moonflower.py
2023-02-22 22:55:11 +01:00

110 lines
3.5 KiB
Python

from typing import Any, Tuple
import pygame as pg
from effects.effect import Effect
from util.color import Colors
from util.transform import transform_bounce
import random
import math
from typing import Union, Generator
def calc_radii(size, f):
r_c = size / (5 * f + 2)
r_a = size / 2 - r_c
return r_c, r_a
class Moonflower(Effect):
def __init__(
self,
bounds: pg.Rect,
colors: Tuple[
Union[pg.Color, Generator[pg.Color, None, None]],
Union[pg.Color, Generator[pg.Color, None, None]],
],
beat_color: bool = False,
size: int = 100,
velocity: Tuple[int, int] = (1, 10),
rot_speed: float = 5,
outer: int = 5,
x_factor: Tuple[float, float] = (0.1, 1),
y_factor: Tuple[float, float] = (0.1, 1),
*groups: pg.sprite.Group
) -> None:
self.min_velocity = velocity[0]
self.max_velocity = velocity[1]
self.rot_speed = rot_speed
self.rotation = 0.0
self.velocity = random.randint(self.min_velocity, self.max_velocity)
# self.ticks = random.randint(0, 360)
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,
),
*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.bouncer)
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.bouncer.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
# self.ticks += int(self.velocity / 180 * math.pi)
self.velocity = random.randint(self.min_velocity, self.max_velocity)