from effects.effect import MovingEffect from typing import Any, Optional from typing import Union, Generator from util.color import Colors import math import pygame as pg import random from util.transform import PositionGenerator class BouncingSpot(MovingEffect): def __init__( self, bounds: pg.Rect, color: Union[pg.Color, Generator[pg.Color, None, None]], sizes=(10, 100), velocity=(1, 10), mover: Optional[PositionGenerator] = None, *groups: pg.sprite.Group ) -> None: self.min_size = sizes[0] self.max_size = sizes[1] self.min_velocity = velocity[0] self.max_velocity = velocity[1] self.velocity = random.randint(self.min_velocity, self.max_velocity) self.ticks = random.randint(0, 360) self.color = color size = (math.sin(self.ticks) / 2 + 0.5) * ( self.max_size - self.min_size ) + self.min_size image = pg.Surface((self.max_size, self.max_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 next(self.mover) self.update(is_beat=False) def update(self, *args: Any, **kwargs: Any) -> None: new_size = (math.sin(self.ticks) / 2 + 0.5) * ( self.max_size - self.min_size ) + self.min_size new_scale = new_size - self.rect.width if kwargs["is_beat"]: new_scale *= 1.5 self.rect.inflate_ip(new_scale, new_scale) self.rect.center = self.mover.send((self.rect.size, kwargs["is_beat"])) self.image.fill(Colors.Black) pg.draw.ellipse( self.image, self.color if isinstance(self.color, pg.Color) else next(self.color), ((0, 0), self.rect.size), ) self.ticks += int(self.velocity / 180 * math.pi) self.velocity = random.randint(self.min_velocity, self.max_velocity)