from typing import Any import pygame as pg from effects.effect import Effect, Colors import random import math from typing import Union, Generator class BouncingSpot(Effect): def __init__( self, bounds: pg.Rect, color: Union[pg.Color, Generator[pg.Color, None, None]], sizes=(10, 100), velocity=(1, 10), x_factor=(0.1, 1), y_factor=(0.1, 1), *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.x_factor = random.uniform(x_factor[0], x_factor[1]) self.y_factor = random.uniform(y_factor[0], y_factor[1]) 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=image, rect=pg.Rect( bounds.centerx - size / 2, bounds.centery - size / 2, size, size, ), *groups ) self.bounds = bounds self.update() 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 self.rect.inflate_ip(new_scale, new_scale) self.rect.centerx = ( 0.4 * math.cos(self.x_factor * self.ticks) * self.bounds.width + self.bounds.centerx ) self.rect.centery = ( 0.4 * math.sin(self.y_factor * self.ticks) * self.bounds.height + self.bounds.centery ) 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 += self.velocity / 180 * math.pi self.velocity = random.randint(self.min_velocity, self.max_velocity)