import pygame as pg from typing import Iterator, List from random import choice, randint, randrange from effects.chase_circle import ChaseCircle from effects.effect import Effect from effects.line import Lines from effects.rectangle import Rectangle from util.color import ( color_darken, color_randomize, color_static, color_strobe, color_wheel, Colors, ) # from effects.crazypolys import CrazyPolys from effects.drops import Drops from effects.bouncingspot import BouncingSpot from effects.doublespot import DoubleSpot from effects.moonflower import Moonflower from effects.rainbowwave import RainbowWave from effects.rotatingpoly import RotatingPoly from effects.scanreticle import ScanReticle # from effects.spiro import Spiro from effects.starfield import Starfield from util.transform import ( transform_bounce, transform_falling, transform_oscillate, transform_static, ) class Presets: def __init__(self, bounds: pg.Rect, beat_reactive: bool = False) -> None: self.bounds = bounds self.beat_reactive = beat_reactive self.shuffles = list(iter(self)) * 2 def default(self) -> List[Effect]: return self.DoubleBouncingSpotsColorWheel() def __getitem__(self, idx: str) -> List[Effect]: return getattr(self, idx)() def __contains__(self, idx: str) -> bool: return hasattr(self, idx) def __iter__(self) -> Iterator[str]: return ( func for func in dir(self) if callable(getattr(self, func)) and not (func.startswith("__") or func == "randomize") ) def randomize(self) -> str: selected = choice(self.shuffles) self.shuffles.remove(selected) if not self.shuffles: self.shuffles = list(iter(self)) * 2 return selected # return choice( # [ # func # for func in dir(self) # if callable(getattr(self, func)) # and not (func.startswith("__") or func == "randomize") # ] # ) def DoubleSpotRandomColor(self) -> List[Effect]: return [ DoubleSpot( bounds=self.bounds, color=color_wheel(increase=30), beat_adapt=self.beat_reactive, radius=100, fade_out=True, fade_in=True, hold=60, ) ] def DoubleBouncingSpotsColorWheel(self) -> List[Effect]: return [ BouncingSpot( bounds=self.bounds, color=color_wheel(), sizes=(self.bounds.height / 8, self.bounds.height / 6), mover=transform_bounce( bounds=self.bounds, velocity=(1, 1), x_factor=(1, 1), y_factor=(2.2, 2.2), on_beat_phase=90, ), ), BouncingSpot( bounds=self.bounds, color=color_wheel(hue=180), sizes=(self.bounds.height / 8, self.bounds.height / 6), mover=transform_bounce( bounds=self.bounds, velocity=(1, 1), x_factor=(1, 1), y_factor=(2.2, 2.2), on_beat_phase=180, ), ), ] def CollidingWaves(self) -> List[Effect]: return [ RainbowWave( bounds=pg.rect.Rect(0, 0, self.bounds.width, self.bounds.height), wave_count=5, wave_height=self.bounds.height // 6, thickness=30, mover=transform_oscillate(self.bounds, 60, (0, 0)), ), RainbowWave( bounds=pg.rect.Rect(0, 0, self.bounds.width, self.bounds.height), # hue=180, wave_count=5, wave_height=self.bounds.height // 6, start_phase=120, thickness=20, mover=transform_oscillate( self.bounds, 60, (0, self.bounds.height * 5 // 6) ), ), ] def RainbowWave(self) -> List[Effect]: return [ RainbowWave( bounds=pg.rect.Rect(0, 0, self.bounds.width, self.bounds.height), wave_count=1, color_inc=2, wave_height=self.bounds.height // 3, thickness=30, mover=transform_static(position=(0, 0)), ), ] def FallingWave(self) -> List[Effect]: bounds = pg.rect.Rect(0, 0, self.bounds.width, self.bounds.height // 2) return [ RainbowWave( bounds=bounds, wave_count=8, wave_height=self.bounds.height // 8, thickness=25, hue=30 * randrange(0, 12), color_inc=0, scroll_speed=0, mover=transform_falling( bounds, acceleration=0.8, initial_pos=(0, 0), initial_velocity=0.01, on_beat_reset=True, ), ), ] def BouncingSpotWhite(self) -> List[Effect]: return [ BouncingSpot( bounds=self.bounds, color=color_static(Colors.White), sizes=(self.bounds.height / 3, self.bounds.height / 3), velocity=(1, 1), mover=transform_bounce( bounds=self.bounds, velocity=(1, 1), x_factor=(1, 1), y_factor=(2.2, 2.2), on_beat_phase=180, ), ), ] def RotatingPoly(self) -> List[Effect]: return [ RotatingPoly( bounds=self.bounds, color=color_wheel(increase=(75 if self.beat_reactive else 0)), beat_color=self.beat_reactive, size=int(self.bounds.height * 0.8), outer=randint(3, 8), rot_speed=1, mover=transform_bounce( bounds=self.bounds, velocity=(0.5, 0.5), x_factor=(0.5, 1.5), y_factor=(0.5, 3), ), ) ] def Moonflower(self) -> List[Effect]: return [ Moonflower( bounds=self.bounds, colors=( color_wheel(increase=(75 if self.beat_reactive else 0)), color_wheel(hue=180, increase=(75 if self.beat_reactive else 0)), ), beat_color=self.beat_reactive, size=self.bounds.height // 2, outer=5, inner_factor=0.3, rot_speed=1.5, mover=transform_bounce( bounds=self.bounds, velocity=(0.5, 1.5), x_factor=(0.5, 1.5), y_factor=(0.5, 1.5), ), ) ] def DoubleMoonflower(self) -> List[Effect]: hue_left = randrange(0, 360) hue_right = randrange(0, 360) size = int(self.bounds.height * 0.75) return [ Moonflower( bounds=self.bounds, colors=( color_wheel( hue=hue_left, increase=(75 if self.beat_reactive else 0) ), color_wheel( hue=180 + hue_left, increase=(75 if self.beat_reactive else 0) ), ), beat_color=self.beat_reactive, size=size, outer=7, inner_factor=0.5, rot_speed=-1.5, mover=transform_static(position=(size // 2, self.bounds.height // 2)), ), Moonflower( bounds=self.bounds, colors=( color_wheel( hue=hue_right, increase=(75 if self.beat_reactive else 0) ), color_wheel( hue=180 + hue_right, increase=(75 if self.beat_reactive else 0) ), ), beat_color=self.beat_reactive, size=size, outer=7, inner_factor=0.5, rot_speed=1.7, mover=transform_static( position=(self.bounds.width - size // 2, self.bounds.height // 2) ), ), ] def NestedMoonflower(self) -> List[Effect]: hue_left = randrange(0, 12) * 30 hue_right = (hue_left + 180) % 360 # hue_right = randrange(0, 360) size = int(self.bounds.height * 0.8) return [ Moonflower( bounds=self.bounds, colors=( color_wheel( hue=hue_left, increase=(15 if self.beat_reactive else 0) ), color_wheel( hue=180 + hue_left, increase=(15 if self.beat_reactive else 0) ), ), beat_color=self.beat_reactive, size=size, outer=7, inner_factor=0.5, rot_speed=-1.5, mover=transform_static( position=(self.bounds.width // 2, self.bounds.height // 2) ), ), Moonflower( bounds=self.bounds, colors=( color_wheel( hue=hue_right, increase=(15 if self.beat_reactive else 0) ), color_wheel( hue=180 + hue_right, increase=(15 if self.beat_reactive else 0) ), ), beat_color=self.beat_reactive, size=int(size * 0.6), outer=7, inner_factor=0.3, rot_speed=1, mover=transform_static( position=(self.bounds.width // 2, self.bounds.height // 2) ), ), ] def WhiteStarfield(self) -> List[Effect]: return [ Starfield( bounds=self.bounds, color=color_static(Colors.White), # color=color_randomize(), fade_in=True, fade_out=True, # radius=30, star_factor=1, hold=60 * 2, # beat_adapt=True, ) ] def ColorStarfield(self) -> List[Effect]: return [ Starfield( bounds=self.bounds, color=color_randomize(), fade_in=True, fade_out=True, # radius=30, star_factor=1, hold=60 * 2, beat_adapt=True, ) ] def GreenBlueDrops(self) -> List[Effect]: return [ Drops( bounds=self.bounds, colors=( color_static(Colors.Green), color_static(color_darken(Colors.Blue, 0.2)), ), sizes=(self.bounds.width // 40, self.bounds.width // 35), drop_rate=0.1, drop_acceleration=0.3, ) ] def ScanReticle(self) -> List[Effect]: return [ ScanReticle( self.bounds, (color_static(Colors.Red), color_static(Colors.White)), mover=transform_bounce( bounds=self.bounds, velocity=(0.5, 1), x_factor=(2, 2), y_factor=(0.5, 1), ), ) ] # def FallingLine(self) -> List[Effect]: # bounds = pg.rect.Rect(0, 0, self.bounds.width, 30) # return [ # Lines( # bounds=bounds, # vectors=(((0, 15), (self.bounds.width, 15), color_wheel()),), # thickness=30, # mover=transform_falling( # bounds, # acceleration=0.8, # initial_pos=(0, 0), # initial_velocity=0.01, # on_beat_reset=True, # ), # ), # ] def StrobeLine(self) -> List[Effect]: thickness = 50 bounds = pg.rect.Rect(0, 0, self.bounds.width, thickness) return [ Lines( bounds=bounds, vectors=( ( (0, thickness // 2), (self.bounds.width, thickness // 2), color_strobe(color=color_wheel(), rate=(4, 60)), ), ), thickness=thickness, mover=transform_static((0, 0)), ), Lines( bounds=bounds, vectors=( ( (0, thickness // 2), (self.bounds.width, thickness // 2), color_strobe(color=color_wheel(), rate=(4, 10)), ), ), thickness=thickness, mover=transform_static((0, self.bounds.height - thickness)), ), ] # def Spiro(self) -> List[Effect]: # return [ # Spiro( # bounds=self.bounds, # color=color_wheel(increase=2), # sizes=(self.bounds.height, self.bounds.height), # velocity=(0.1, 0.4), # mover=transform_bounce( # self.bounds, # velocity=(0.1, 0.4), # x_factor=(1, 1), # y_factor=(0.5, 1.5), # ), # ), # ] # def CrazyPolys(self) -> List[Effect]: # return [ # CrazyPolys( # bounds=self.bounds, # color=color_wheel(increase=2), # sizes=(self.bounds.height, self.bounds.height), # velocity=(0.1, 0.4), # y_factor=(0.5, 1.5), # ), # ] def SpotRow(self) -> List[Effect]: count = 8 size = self.bounds.width // (count * 2) return [ BouncingSpot( bounds=self.bounds, color=color_wheel(hue=3 * 360 // count * i, increase=60), sizes=(size, size), velocity=(1, 1), on_beat_color=True, mover=transform_static( ( size + size * 2 * i, size, ) ), ) for i in range(count) ] def OscillateSpotRow(self) -> List[Effect]: count = 4 size = self.bounds.width // (count * 2) return [ BouncingSpot( bounds=self.bounds, color=color_wheel(hue=180 * i, increase=120), sizes=(size * 1.5, size * 1.5), velocity=(1, 1), on_beat_color=True, mover=transform_oscillate( bounds=pg.Rect( size + size * 2 * i, size * 1.5 // 2, size * 1.5, self.bounds.height, ), period=120, auto_period=4, ), ) for i in range(count) ] def StrobeRect(self) -> List[Effect]: thickness = 50 color_lr = color_wheel(hue=0, increase=1, repeat=4) color_ud = color_wheel(hue=180, increase=1, repeat=4) color_lr_s = color_strobe(color=color_lr, rate=(30, 120), flash_color=color_ud) color_ud_s = color_strobe(color=color_ud, rate=(30, 120), flash_color=color_lr) return [ Lines( bounds=self.bounds, vectors=( ( (0, thickness // 2), (self.bounds.width, thickness // 2), color_ud_s, ), ( (0, self.bounds.height - thickness // 2), (self.bounds.width, self.bounds.height - thickness // 2), color_ud_s, ), ), thickness=thickness, mover=transform_static((0, 0)), ), Lines( bounds=self.bounds, vectors=( ( (thickness // 2, 0), (thickness // 2, self.bounds.height), color_lr_s, ), ( (self.bounds.width - thickness // 2, 0), (self.bounds.width - thickness // 2, self.bounds.height), color_lr_s, ), ), thickness=thickness, mover=transform_static((0, 0)), ), ] def ChaseCircle(self) -> List[Effect]: return [ ChaseCircle( bounds=self.bounds, colors=( color_wheel(increase=(75 if self.beat_reactive else 0)), color_wheel(hue=180, increase=(75 if self.beat_reactive else 0)), ), on_beat_color=self.beat_reactive, size=int(self.bounds.height * 0.7), rot_speed=5, thickness=80, size_factor=1, mover=transform_bounce( bounds=self.bounds, velocity=(0.1, 0.5), x_factor=(0.5, 1), y_factor=(0.1, 0.3), ), ) ] def ChaseCircleLine(self) -> List[Effect]: return [ ChaseCircle( bounds=self.bounds, colors=( color_wheel(increase=(75 if self.beat_reactive else 0)), color_wheel(hue=180, increase=(75 if self.beat_reactive else 0)), ), on_beat_color=self.beat_reactive, size=int(self.bounds.height * 0.7), rot_speed=-20, thickness=80, size_factor=0.2, mover=transform_bounce( bounds=self.bounds, velocity=(0.1, 0.5), x_factor=(0.5, 1), y_factor=(0.1, 0.3), ), ) ] # def Rectangle(self) -> List[Effect]: # return [ # Rectangle( # bounds=self.bounds, # color=color_wheel(increase=(75 if self.beat_reactive else 1)), # size=int(self.bounds.height*0.9), # aspect=1.0, # rot_speed=0.5, # thickness=80, # mover=transform_bounce( # bounds=self.bounds, # velocity=(0.1, 0.5), # x_factor=(0.5, 1), # y_factor=(0.1, 0.3), # ), # ) # ]