597 lines
19 KiB
Python
597 lines
19 KiB
Python
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),
|
|
# ),
|
|
# )
|
|
# ]
|