refactor effect.py into utils
This commit is contained in:
parent
5c14542a6c
commit
f7691f2545
17 changed files with 292 additions and 279 deletions
49
beamshow.py
49
beamshow.py
|
@ -1,13 +1,13 @@
|
|||
from argparse import ArgumentParser
|
||||
import time
|
||||
from typing import Generator, List, Tuple
|
||||
|
||||
import pygame as pg
|
||||
import sys
|
||||
|
||||
from effects.effect import Effect, Colors, color_darken, color_fadeout, color_wheel
|
||||
from effects.effect import Effect
|
||||
from effects.presets import Presets
|
||||
from audio import AudioProcess
|
||||
from util.color import Colors
|
||||
from util.audio import AudioProcess
|
||||
|
||||
|
||||
def print_displays() -> None:
|
||||
|
@ -146,9 +146,6 @@ class Beamshow:
|
|||
framecounter = 0
|
||||
blackout = False
|
||||
single_random = False
|
||||
# taps = []
|
||||
# tap_mean = 0
|
||||
# last_beat = 0
|
||||
fps_slidewindow = []
|
||||
frames_per_beat = 0
|
||||
while True:
|
||||
|
@ -158,22 +155,15 @@ class Beamshow:
|
|||
if is_beat:
|
||||
if self.beat_skip_counter > 0:
|
||||
is_beat = False
|
||||
print(' skip')
|
||||
print(" skip")
|
||||
self.beat_skip_counter -= 1
|
||||
else:
|
||||
print('beat')
|
||||
print("beat")
|
||||
self.beat_skip_counter = self.beat_factor - 1
|
||||
|
||||
# is_beat = False
|
||||
fps_mean = (
|
||||
sum(fps_slidewindow) / len(fps_slidewindow) if fps_slidewindow else 0
|
||||
)
|
||||
# if tap_mean and last_beat:
|
||||
# this_beat = time.time()
|
||||
# is_beat = this_beat >= last_beat + tap_mean
|
||||
# frames_per_beat = fps_mean * tap_mean
|
||||
# if is_beat:
|
||||
# last_beat = this_beat
|
||||
|
||||
common_events = loop.send((is_beat, frames_per_beat))
|
||||
reinitialize = False
|
||||
|
@ -218,41 +208,14 @@ class Beamshow:
|
|||
elif event.key == pg.K_HOME:
|
||||
print("resetting beat timing")
|
||||
self.beat_skip_counter = 0
|
||||
# this_tap = time.time()
|
||||
# last_beat = this_tap
|
||||
# elif event.key == pg.K_END:
|
||||
# print("starting new tap measurement")
|
||||
# taps.clear()
|
||||
elif event.key == pg.K_PAGEUP:
|
||||
self.beat_factor = (
|
||||
self.beat_factor / 2 if self.beat_factor > 1 else 1
|
||||
)
|
||||
print(f"Trigger on every {self.beat_factor} beat")
|
||||
# tap_mean /= 2
|
||||
# print(
|
||||
# f"Taps: Mean {tap_mean:5.3f} s, {60/tap_mean:5.3f} BPM, {fps_mean * tap_mean:5.3f} FPB [x2]"
|
||||
# )
|
||||
elif event.key == pg.K_PAGEDOWN:
|
||||
self.beat_factor = self.beat_factor * 2
|
||||
print(f"Trigger on every {self.beat_factor} beat")
|
||||
# tap_mean *= 2
|
||||
# print(
|
||||
# f"Taps: Mean {tap_mean:5.3f} s, {60/tap_mean:5.3f} BPM, {fps_mean * tap_mean:5.3f} FPB [/2]"
|
||||
# )
|
||||
# elif event.key == pg.K_KP_ENTER or event.key == pg.K_RETURN:
|
||||
# this_tap = time.time()
|
||||
# if taps and this_tap - taps[-1] > 10:
|
||||
# print("starting new tap measurement")
|
||||
# taps.clear()
|
||||
# taps.append(this_tap)
|
||||
# last_beat = this_tap
|
||||
# if len(taps) >= 2:
|
||||
# tap_mean = sum(
|
||||
# map(lambda t1, t2: t2 - t1, taps, taps[1:])
|
||||
# ) / (len(taps) - 1)
|
||||
# print(
|
||||
# f"Taps: Mean {tap_mean:5.3f} s, {60/tap_mean:5.3f} BPM, {fps_mean * tap_mean:5.3f} FPB"
|
||||
# )
|
||||
|
||||
if reinitialize:
|
||||
self.window, self.background = self.initialize()
|
||||
|
@ -266,7 +229,7 @@ class Beamshow:
|
|||
self.window.fill(Colors.Black)
|
||||
|
||||
if is_beat:
|
||||
pg.draw.rect(self.window, Colors.White, (0, 0, 30, 30))
|
||||
pg.draw.rect(self.window, Colors.White, (0, 0, 20, 20))
|
||||
|
||||
pg.display.flip()
|
||||
self.clock.tick(60)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
from effects.effect import Effect
|
||||
from typing import Any
|
||||
import pygame as pg
|
||||
from effects.effect import Effect, Colors, transform_bounce
|
||||
import random
|
||||
import math
|
||||
from typing import Union, Generator
|
||||
from util.color import Colors
|
||||
from util.transform import transform_bounce
|
||||
import math
|
||||
import pygame as pg
|
||||
import random
|
||||
|
||||
|
||||
class BouncingSpot(Effect):
|
||||
|
@ -46,7 +48,7 @@ class BouncingSpot(Effect):
|
|||
bounds=bounds, velocity=velocity, x_factor=x_factor, y_factor=y_factor
|
||||
)
|
||||
next(self.bouncer)
|
||||
self.update()
|
||||
self.update(is_beat=False)
|
||||
|
||||
def update(self, *args: Any, **kwargs: Any) -> None:
|
||||
new_size = (math.sin(self.ticks) / 2 + 0.5) * (
|
||||
|
@ -56,7 +58,7 @@ class BouncingSpot(Effect):
|
|||
new_scale = new_size - self.rect.width
|
||||
self.rect.inflate_ip(new_scale, new_scale)
|
||||
|
||||
self.rect.center = self.bouncer.send(self.rect.size)
|
||||
self.rect.center = self.bouncer.send((self.rect.size, kwargs["is_beat"]))
|
||||
|
||||
self.image.fill(Colors.Black)
|
||||
pg.draw.ellipse(
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
from effects.effect import Effect
|
||||
from typing import Any
|
||||
import pygame as pg
|
||||
from effects.effect import Effect, Colors, transform_bounce
|
||||
import random
|
||||
import math
|
||||
from typing import Union, Generator
|
||||
from util.color import Colors
|
||||
from util.transform import transform_bounce
|
||||
import math
|
||||
import pygame as pg
|
||||
import random
|
||||
|
||||
|
||||
class CrazyPolys(Effect):
|
||||
|
@ -69,7 +71,7 @@ class CrazyPolys(Effect):
|
|||
|
||||
self.size_f = (self.size * 0.6 - 10) / 2 / (self.R + self.r)
|
||||
self.cursor = self.calc_pos()
|
||||
self.update()
|
||||
self.update(is_beat=False)
|
||||
|
||||
def calc_pos(self):
|
||||
x = self.max_size / 2 + self.size_f * (
|
||||
|
@ -98,7 +100,7 @@ class CrazyPolys(Effect):
|
|||
# new_scale = new_size - self.rect.width
|
||||
# self.rect.inflate_ip(new_scale, new_scale)
|
||||
|
||||
self.rect.center = self.bouncer.send(self.rect.size)
|
||||
self.rect.center = self.bouncer.send((self.rect.size, kwargs["is_beat"]))
|
||||
|
||||
self.image.blit(self.background, (0, 0))
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from typing import Any, List, Tuple
|
||||
import pygame as pg
|
||||
from effects.effect import Effect, Colors
|
||||
from effects.effect import Effect
|
||||
from util.color import Colors
|
||||
import random
|
||||
from typing import Union, Generator
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from typing import Any, List, Tuple
|
||||
import pygame as pg
|
||||
from effects.effect import Effect, Colors, color_fade, transform_falling
|
||||
from effects.effect import Effect
|
||||
from util.color import Colors, color_fade
|
||||
from util.transform import transform_falling
|
||||
import random
|
||||
from typing import Union, Generator
|
||||
|
||||
|
@ -38,9 +40,9 @@ class Drop(pg.sprite.Sprite):
|
|||
)
|
||||
next(self.fall)
|
||||
self.finished = False
|
||||
self.update()
|
||||
self.update(is_beat=False)
|
||||
|
||||
def update(self):
|
||||
def update(self, *args, **kwargs):
|
||||
if isinstance(self.color, Generator):
|
||||
pg.draw.ellipse(
|
||||
self.image,
|
||||
|
@ -48,7 +50,9 @@ class Drop(pg.sprite.Sprite):
|
|||
((0, 0), self.rect.size),
|
||||
)
|
||||
if not self.finished:
|
||||
self.rect.topleft = self.fall.send((self.bounds.width, self.bounds.width))
|
||||
self.rect.topleft = self.fall.send(
|
||||
((self.bounds.width, self.bounds.width), kwargs["is_beat"])
|
||||
)
|
||||
if self.rect.bottom >= self.bounds.bottom - self.bounds.width:
|
||||
self.finished = True
|
||||
|
||||
|
@ -117,7 +121,7 @@ class Drops(Effect):
|
|||
|
||||
for drop in self.drops:
|
||||
if not drop.finished:
|
||||
drop.update()
|
||||
drop.update(is_beat=kwargs["is_beat"])
|
||||
drop.draw(self.image)
|
||||
|
||||
if self.drops:
|
||||
|
|
|
@ -1,202 +1,6 @@
|
|||
from dataclasses import dataclass
|
||||
import math
|
||||
import random
|
||||
from typing import Generator, Literal, Tuple
|
||||
import pygame as pg
|
||||
|
||||
|
||||
def copy_color(source: pg.Color) -> pg.Color:
|
||||
return pg.Color(source.r, source.g, source.b, source.a)
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class Colors:
|
||||
Black = pg.Color(0, 0, 0)
|
||||
White = pg.Color(255, 255, 255)
|
||||
Red = pg.Color(255, 0, 0)
|
||||
Green = pg.Color(0, 255, 0)
|
||||
Blue = pg.Color(0, 0, 255)
|
||||
Cyan = pg.Color(0, 255, 255)
|
||||
Yellow = pg.Color(255, 255, 0)
|
||||
Magenta = pg.Color(255, 0, 255)
|
||||
|
||||
|
||||
def color_wheel(hue=0, increase=1) -> Generator[pg.Color, None, None]:
|
||||
color = copy_color(Colors.Red)
|
||||
h, s, l, a = color.hsla
|
||||
h = hue
|
||||
|
||||
while True:
|
||||
color.hsla = h, s, l, a
|
||||
yield color
|
||||
h = (h + increase) % 360
|
||||
|
||||
|
||||
def color_randomize() -> Generator[pg.Color, None, None]:
|
||||
color = copy_color(Colors.Red)
|
||||
h, s, l, a = color.hsla
|
||||
color.hsla = random.randrange(0, 360 // 5) * 5, s, l, a
|
||||
|
||||
while True:
|
||||
yield color
|
||||
color.hsla = random.randrange(0, 360 // 5) * 5, s, l, a
|
||||
|
||||
|
||||
def color_fadeout(
|
||||
initial_color: pg.Color, fade_speed: float
|
||||
) -> Generator[pg.Color, None, None]:
|
||||
color = copy_color(initial_color)
|
||||
h, s, l, a = color.hsla
|
||||
l_float = float(l)
|
||||
|
||||
while True:
|
||||
yield color
|
||||
color.hsla = h, s, int(l_float), a
|
||||
l_float -= fade_speed
|
||||
if l_float < 0:
|
||||
l_float = 0
|
||||
|
||||
|
||||
def color_fade(
|
||||
initial_color: pg.Color, end_color: pg.Color, duration: int
|
||||
) -> Generator[pg.Color, None, None]:
|
||||
color = copy_color(initial_color)
|
||||
h, s, l, a = color.hsla
|
||||
h2, s2, l2, a2 = end_color.hsla
|
||||
h_inc = (h2 - h) / duration
|
||||
s_inc = (s2 - s) / duration
|
||||
l_inc = (l2 - l) / duration
|
||||
a_inc = (a2 - a) / duration
|
||||
h_f = float(h)
|
||||
s_f = float(s)
|
||||
l_f = float(l)
|
||||
a_f = float(a)
|
||||
|
||||
while True:
|
||||
yield color
|
||||
color.hsla = int(h_f), int(s_f), int(l_f), int(a_f)
|
||||
if h_f < h2:
|
||||
h_f += h_inc
|
||||
if s_f < s2:
|
||||
s_f += s_inc
|
||||
if l_f < l2:
|
||||
l_f += l_inc
|
||||
if a_f < a2:
|
||||
a_f += a_inc
|
||||
|
||||
|
||||
def color_darken(color: pg.Color, factor: float) -> pg.Color:
|
||||
h, s, l, a = color.hsla
|
||||
new_color = pg.Color(0, 0, 0, 255)
|
||||
new_color.hsla = h, s, l * factor, a
|
||||
return new_color
|
||||
|
||||
|
||||
def rainbow_surface(
|
||||
image: pg.Surface,
|
||||
orientation: Literal["h", "v"] = "h",
|
||||
hue: int = 0,
|
||||
increase: int = 1,
|
||||
):
|
||||
wheel = color_wheel(hue, increase)
|
||||
if orientation == "h":
|
||||
h = image.get_height()
|
||||
for x in range(image.get_width()):
|
||||
pg.draw.line(image, next(wheel), (x, 0), (x, h))
|
||||
elif orientation == "v":
|
||||
w = image.get_width()
|
||||
for y in range(image.get_height()):
|
||||
pg.draw.line(image, next(wheel), (0, y), (w, y))
|
||||
|
||||
|
||||
def transform_bounce(
|
||||
bounds: pg.Rect,
|
||||
velocity: Tuple[float, float],
|
||||
x_factor: Tuple[float, float],
|
||||
y_factor: Tuple[float, float],
|
||||
) -> Generator[Tuple[int, int], Tuple[int, int], None]:
|
||||
min_velocity = velocity[0]
|
||||
max_velocity = velocity[1]
|
||||
current_velocity = random.uniform(min_velocity, max_velocity)
|
||||
phase = random.uniform(0, 360)
|
||||
current_x_factor = random.uniform(x_factor[0], x_factor[1])
|
||||
current_y_factor = random.uniform(y_factor[0], y_factor[1])
|
||||
|
||||
size_x, size_y = yield (bounds.centerx, bounds.centery)
|
||||
while True:
|
||||
pos_x = int(
|
||||
math.cos(current_x_factor * phase) * (bounds.width - size_x) // 2
|
||||
+ bounds.centerx
|
||||
)
|
||||
pos_y = int(
|
||||
math.sin(current_y_factor * phase) * (bounds.height - size_y) // 2
|
||||
+ bounds.centery
|
||||
)
|
||||
|
||||
phase += current_velocity / 180 * math.pi
|
||||
# current_velocity = random.uniform(min_velocity, max_velocity)
|
||||
size_x, size_y = yield (pos_x, pos_y)
|
||||
|
||||
|
||||
def transform_oscillate(
|
||||
bounds: pg.Rect,
|
||||
period: int,
|
||||
initial_pos: Tuple[int, int] = (-1, -1),
|
||||
) -> Generator[Tuple[int, int], Tuple[int, int], None]:
|
||||
pos_x = float(initial_pos[0] if initial_pos[0] > 0 else bounds.left)
|
||||
pos_y = float(initial_pos[1] if initial_pos[1] > 0 else bounds.top)
|
||||
direction = "+"
|
||||
|
||||
size_x, size_y = yield (bounds.left, bounds.top)
|
||||
|
||||
while True:
|
||||
range_x = bounds.width - size_x
|
||||
range_y = bounds.height - size_y
|
||||
|
||||
inc_x = range_x / period
|
||||
inc_y = range_y / period
|
||||
|
||||
if direction == "+":
|
||||
pos_x = pg.math.clamp(pos_x + inc_x, 0, range_x)
|
||||
pos_y = pg.math.clamp(pos_y + inc_y, 0, range_y)
|
||||
else:
|
||||
pos_x = pg.math.clamp(pos_x - inc_x, 0, range_x)
|
||||
pos_y = pg.math.clamp(pos_y - inc_y, 0, range_y)
|
||||
|
||||
if (inc_x and (pos_x > range_x - inc_x)) or (
|
||||
inc_y and (pos_y > range_y - inc_y)
|
||||
):
|
||||
direction = "-"
|
||||
elif (inc_x and (pos_x < inc_x)) or (inc_y and (pos_y < inc_y)):
|
||||
direction = "+"
|
||||
|
||||
size_x, size_y = yield (int(pos_x), int(pos_y))
|
||||
|
||||
|
||||
def transform_falling(
|
||||
bounds: pg.Rect,
|
||||
acceleration: float,
|
||||
initial_pos: Tuple[int, int],
|
||||
initial_velocity: float = 1.0,
|
||||
) -> Generator[Tuple[int, int], Tuple[int, int], None]:
|
||||
pos_x = float(initial_pos[0])
|
||||
pos_y = float(initial_pos[1])
|
||||
|
||||
size_x, size_y = yield (bounds.left, bounds.top)
|
||||
|
||||
velocity = initial_velocity
|
||||
|
||||
while True:
|
||||
range_y = bounds.height - size_y
|
||||
|
||||
pos_y += velocity
|
||||
velocity += acceleration
|
||||
|
||||
if pos_y > range_y:
|
||||
pos_y = initial_pos[1]
|
||||
velocity = initial_velocity
|
||||
|
||||
size_x, size_y = yield (int(pos_x), int(pos_y))
|
||||
from util.transform import Mover
|
||||
|
||||
|
||||
class Effect(pg.sprite.Sprite):
|
||||
|
@ -209,3 +13,11 @@ class Effect(pg.sprite.Sprite):
|
|||
|
||||
def draw(self, surface: pg.Surface):
|
||||
surface.blit(self.image, self.rect)
|
||||
|
||||
|
||||
class MovingEffect(Effect):
|
||||
def __init__(
|
||||
self, image: pg.Surface, rect: pg.Rect, mover: Mover, *groups: pg.sprite.Group
|
||||
) -> None:
|
||||
super().__init__(image, rect, *groups)
|
||||
self.mover = mover
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from typing import Any, Tuple
|
||||
import pygame as pg
|
||||
from effects.effect import Effect, Colors, transform_bounce
|
||||
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
|
||||
|
@ -60,7 +62,7 @@ class Moonflower(Effect):
|
|||
)
|
||||
self.bounds = bounds
|
||||
self.bouncer = transform_bounce(
|
||||
bounds=bounds, velocity=velocity, x_factor=x_factor, y_factor=y_factor
|
||||
bounds=bounds, velocity=velocity, x_factor=x_factor, y_factor=y_factor, on_beat_random_phase=True
|
||||
)
|
||||
next(self.bouncer)
|
||||
self.o_color = (
|
||||
|
@ -76,7 +78,7 @@ class Moonflower(Effect):
|
|||
self.update(is_beat=False)
|
||||
|
||||
def update(self, *args: Any, **kwargs: Any) -> None:
|
||||
self.rect.center = self.bouncer.send(self.rect.size)
|
||||
self.rect.center = self.bouncer.send((self.rect.size, kwargs["is_beat"]))
|
||||
|
||||
self.image.fill(Colors.Black)
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from typing import Any, Tuple
|
||||
import pygame as pg
|
||||
from effects.effect import Effect, Colors, rainbow_surface, transform_oscillate
|
||||
from effects.effect import Effect
|
||||
from util.color import Colors, rainbow_surface
|
||||
from util.transform import transform_oscillate
|
||||
import math
|
||||
|
||||
|
||||
|
@ -69,7 +71,7 @@ class MovingWave(Effect):
|
|||
width=thickness,
|
||||
)
|
||||
|
||||
self.update()
|
||||
self.update(is_beat=False)
|
||||
|
||||
def update(self, *args: Any, **kwargs: Any) -> None:
|
||||
|
||||
|
@ -78,7 +80,9 @@ class MovingWave(Effect):
|
|||
# rainbow_surface(self.image)
|
||||
|
||||
if self.oscillator:
|
||||
pos = self.oscillator.send((self.bounds.width, self.wave_height))
|
||||
pos = self.oscillator.send(
|
||||
((self.bounds.width, self.wave_height), kwargs["is_beat"])
|
||||
)
|
||||
# pg.draw.rect(self.image, Colors.Black, (0, 0, self.bounds.width, pos[1]))
|
||||
# pg.draw.rect(
|
||||
# self.image,
|
||||
|
|
|
@ -3,9 +3,12 @@ import pygame as pg
|
|||
from typing import List
|
||||
|
||||
from random import choice, randint
|
||||
|
||||
from effects.effect import Effect
|
||||
from util.color import color_darken, color_randomize, color_wheel, Colors
|
||||
|
||||
from effects.crazypolys import CrazyPolys
|
||||
from effects.drops import Drops
|
||||
from effects.effect import Effect, color_darken, color_randomize, color_wheel, Colors
|
||||
from effects.bouncingspot import BouncingSpot
|
||||
from effects.doublespot import DoubleSpot
|
||||
from effects.moonflower import Moonflower
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from typing import Any, Tuple
|
||||
import pygame as pg
|
||||
from effects.effect import Effect, Colors, transform_bounce
|
||||
from effects.effect import Effect
|
||||
from util.color import Colors
|
||||
from util.transform import transform_bounce
|
||||
import math
|
||||
from typing import Union, Generator
|
||||
|
||||
|
@ -64,7 +66,7 @@ class RotatingPoly(Effect):
|
|||
self.update(is_beat=False)
|
||||
|
||||
def update(self, *args: Any, **kwargs: Any) -> None:
|
||||
self.rect.center = self.bouncer.send(self.rect.size)
|
||||
self.rect.center = self.bouncer.send((self.rect.size, kwargs["is_beat"]))
|
||||
|
||||
self.image.fill(Colors.Black)
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from typing import Any, Tuple
|
||||
import pygame as pg
|
||||
from effects.effect import Effect, Colors, transform_bounce
|
||||
from effects.effect import Effect
|
||||
from util.color import Colors
|
||||
from util.transform import transform_bounce
|
||||
import random
|
||||
from typing import Union, Generator
|
||||
|
||||
|
@ -35,11 +37,13 @@ class ScanReticle(Effect):
|
|||
bounds=bounds, velocity=velocity, x_factor=x_factor, y_factor=y_factor
|
||||
)
|
||||
next(self.bouncer)
|
||||
self.update()
|
||||
self.update(is_beat=False)
|
||||
|
||||
def update(self, *args: Any, **kwargs: Any) -> None:
|
||||
|
||||
target = self.bouncer.send((self.rect_size, self.rect_size))
|
||||
target = self.bouncer.send(
|
||||
((self.rect_size, self.rect_size), kwargs["is_beat"])
|
||||
)
|
||||
|
||||
self.image.fill(Colors.Black)
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from typing import Any
|
||||
import pygame as pg
|
||||
from effects.effect import Effect, Colors, copy_color, transform_bounce
|
||||
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
|
||||
|
@ -23,7 +25,7 @@ class Spiro(Effect):
|
|||
self.min_velocity = velocity[0]
|
||||
self.max_velocity = velocity[1]
|
||||
|
||||
self.velocity = 0.1 # random.uniform(self.min_velocity, self.max_velocity)
|
||||
self.velocity = 0.1 # random.uniform(self.min_velocity, self.max_velocity)
|
||||
self.ticks = 0.0
|
||||
self.color = color
|
||||
self.size = self.max_size
|
||||
|
@ -32,8 +34,8 @@ class Spiro(Effect):
|
|||
image.set_colorkey(Colors.Black)
|
||||
|
||||
self.R = random.randint(self.max_size / 6, self.max_size / 2)
|
||||
self.a = 3/random.randint(4, 10) #random.uniform(0, 1)
|
||||
self.k = 3/random.randint(4, 10) #random.uniform(0, 1)
|
||||
self.a = 3 / random.randint(4, 10) # random.uniform(0, 1)
|
||||
self.k = 3 / random.randint(4, 10) # random.uniform(0, 1)
|
||||
|
||||
self.scan_speed = random.randint(1, 100)
|
||||
|
||||
|
@ -65,7 +67,7 @@ class Spiro(Effect):
|
|||
next(self.bouncer)
|
||||
|
||||
self.cursor = self.calc_pos()
|
||||
self.update()
|
||||
self.update(is_beat=False)
|
||||
|
||||
def calc_pos(self):
|
||||
x = self.max_size / 2 + self.R * (
|
||||
|
@ -86,7 +88,7 @@ class Spiro(Effect):
|
|||
# new_scale = new_size - self.rect.width
|
||||
# self.rect.inflate_ip(new_scale, new_scale)
|
||||
|
||||
self.rect.center = self.bouncer.send(self.rect.size)
|
||||
self.rect.center = self.bouncer.send((self.rect.size, kwargs["is_beat"]))
|
||||
|
||||
self.image.blit(self.background, (0, 0))
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from typing import Any, List, Tuple
|
||||
import pygame as pg
|
||||
from effects.effect import Effect, Colors
|
||||
from effects.effect import Effect
|
||||
from util.color import Colors
|
||||
import random
|
||||
from typing import Union, Generator
|
||||
|
||||
|
@ -124,7 +125,7 @@ class Starfield(Effect):
|
|||
self.image.fill(Colors.Black)
|
||||
|
||||
if self.beat_adapt and kwargs["frames_per_beat"]:
|
||||
hold = 3*kwargs["frames_per_beat"] - 2
|
||||
hold = 3 * kwargs["frames_per_beat"] - 2
|
||||
self.fade_in_time = int(hold // 10 if self.fade_in_time else 0)
|
||||
self.fade_out_time = int(hold * 0.8 if self.fade_out_time else 0)
|
||||
self.hold_time = int(hold - self.fade_in_time)
|
||||
|
@ -135,7 +136,7 @@ class Starfield(Effect):
|
|||
self.time_to_next == 0 and (not self.beat_adapt or kwargs["is_beat"])
|
||||
) and len(self.stars) < int(self.num_stars * 0.8):
|
||||
missing_stars = self.num_stars - len(self.stars)
|
||||
for _ in range(random.randint(missing_stars // 3, missing_stars//2)):
|
||||
for _ in range(random.randint(missing_stars // 3, missing_stars // 2)):
|
||||
star_color = (
|
||||
self.color if isinstance(self.color, pg.Color) else next(self.color)
|
||||
)
|
||||
|
|
0
util/__init__.py
Normal file
0
util/__init__.py
Normal file
|
@ -66,6 +66,7 @@ class AudioProcess:
|
|||
is_beat = self.tempo(samples)
|
||||
if is_beat:
|
||||
with self.lock:
|
||||
# print(self.tempo.get)
|
||||
self.is_beat = True
|
||||
# samples += click
|
||||
# print("tick") # avoid print in audio callback
|
108
util/color.py
Normal file
108
util/color.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
from dataclasses import dataclass
|
||||
import random
|
||||
from typing import Generator, Literal
|
||||
import pygame as pg
|
||||
|
||||
|
||||
def copy_color(source: pg.Color) -> pg.Color:
|
||||
return pg.Color(source.r, source.g, source.b, source.a)
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class Colors:
|
||||
Black = pg.Color(0, 0, 0)
|
||||
White = pg.Color(255, 255, 255)
|
||||
Red = pg.Color(255, 0, 0)
|
||||
Green = pg.Color(0, 255, 0)
|
||||
Blue = pg.Color(0, 0, 255)
|
||||
Cyan = pg.Color(0, 255, 255)
|
||||
Yellow = pg.Color(255, 255, 0)
|
||||
Magenta = pg.Color(255, 0, 255)
|
||||
|
||||
|
||||
def color_wheel(hue=0, increase=1) -> Generator[pg.Color, None, None]:
|
||||
color = copy_color(Colors.Red)
|
||||
h, s, l, a = color.hsla
|
||||
h = hue
|
||||
|
||||
while True:
|
||||
color.hsla = h, s, l, a
|
||||
yield color
|
||||
h = (h + increase) % 360
|
||||
|
||||
|
||||
def color_randomize() -> Generator[pg.Color, None, None]:
|
||||
color = copy_color(Colors.Red)
|
||||
h, s, l, a = color.hsla
|
||||
color.hsla = random.randrange(0, 360 // 5) * 5, s, l, a
|
||||
|
||||
while True:
|
||||
yield color
|
||||
color.hsla = random.randrange(0, 360 // 5) * 5, s, l, a
|
||||
|
||||
|
||||
def color_fadeout(
|
||||
initial_color: pg.Color, fade_speed: float
|
||||
) -> Generator[pg.Color, None, None]:
|
||||
color = copy_color(initial_color)
|
||||
h, s, l, a = color.hsla
|
||||
l_float = float(l)
|
||||
|
||||
while True:
|
||||
yield color
|
||||
color.hsla = h, s, int(l_float), a
|
||||
l_float -= fade_speed
|
||||
if l_float < 0:
|
||||
l_float = 0
|
||||
|
||||
|
||||
def color_fade(
|
||||
initial_color: pg.Color, end_color: pg.Color, duration: int
|
||||
) -> Generator[pg.Color, None, None]:
|
||||
color = copy_color(initial_color)
|
||||
h, s, l, a = color.hsla
|
||||
h2, s2, l2, a2 = end_color.hsla
|
||||
h_inc = (h2 - h) / duration
|
||||
s_inc = (s2 - s) / duration
|
||||
l_inc = (l2 - l) / duration
|
||||
a_inc = (a2 - a) / duration
|
||||
h_f = float(h)
|
||||
s_f = float(s)
|
||||
l_f = float(l)
|
||||
a_f = float(a)
|
||||
|
||||
while True:
|
||||
yield color
|
||||
color.hsla = int(h_f), int(s_f), int(l_f), int(a_f)
|
||||
if h_f < h2:
|
||||
h_f += h_inc
|
||||
if s_f < s2:
|
||||
s_f += s_inc
|
||||
if l_f < l2:
|
||||
l_f += l_inc
|
||||
if a_f < a2:
|
||||
a_f += a_inc
|
||||
|
||||
|
||||
def color_darken(color: pg.Color, factor: float) -> pg.Color:
|
||||
h, s, l, a = color.hsla
|
||||
new_color = pg.Color(0, 0, 0, 255)
|
||||
new_color.hsla = h, s, l * factor, a
|
||||
return new_color
|
||||
|
||||
|
||||
def rainbow_surface(
|
||||
image: pg.Surface,
|
||||
orientation: Literal["h", "v"] = "h",
|
||||
hue: int = 0,
|
||||
increase: int = 1,
|
||||
):
|
||||
wheel = color_wheel(hue, increase)
|
||||
if orientation == "h":
|
||||
h = image.get_height()
|
||||
for x in range(image.get_width()):
|
||||
pg.draw.line(image, next(wheel), (x, 0), (x, h))
|
||||
elif orientation == "v":
|
||||
w = image.get_width()
|
||||
for y in range(image.get_height()):
|
||||
pg.draw.line(image, next(wheel), (0, y), (w, y))
|
102
util/transform.py
Normal file
102
util/transform.py
Normal file
|
@ -0,0 +1,102 @@
|
|||
import math
|
||||
import random
|
||||
from typing import Callable, Generator, Optional, Tuple
|
||||
import pygame as pg
|
||||
|
||||
PositionGenerator = Generator[
|
||||
Tuple[int, int], Tuple[Tuple[int, int], Optional[bool]], None
|
||||
]
|
||||
Mover = Callable[(...), PositionGenerator]
|
||||
|
||||
|
||||
def transform_bounce(
|
||||
bounds: pg.Rect,
|
||||
velocity: Tuple[float, float],
|
||||
x_factor: Tuple[float, float],
|
||||
y_factor: Tuple[float, float],
|
||||
on_beat_random_phase: bool = False,
|
||||
) -> PositionGenerator:
|
||||
min_velocity = velocity[0]
|
||||
max_velocity = velocity[1]
|
||||
current_velocity = random.uniform(min_velocity, max_velocity)
|
||||
phase = random.uniform(0, 360)
|
||||
current_x_factor = random.uniform(x_factor[0], x_factor[1])
|
||||
current_y_factor = random.uniform(y_factor[0], y_factor[1])
|
||||
|
||||
(size_x, size_y), is_beat = yield (bounds.centerx, bounds.centery)
|
||||
while True:
|
||||
pos_x = int(
|
||||
math.cos(current_x_factor * phase) * (bounds.width - size_x) // 2
|
||||
+ bounds.centerx
|
||||
)
|
||||
pos_y = int(
|
||||
math.sin(current_y_factor * phase) * (bounds.height - size_y) // 2
|
||||
+ bounds.centery
|
||||
)
|
||||
|
||||
phase += current_velocity / 180 * math.pi
|
||||
if on_beat_random_phase and is_beat:
|
||||
phase += random.randrange(0, 360)
|
||||
(size_x, size_y), _ = yield (pos_x, pos_y)
|
||||
|
||||
|
||||
def transform_oscillate(
|
||||
bounds: pg.Rect,
|
||||
period: int,
|
||||
initial_pos: Tuple[int, int] = (-1, -1),
|
||||
) -> PositionGenerator:
|
||||
pos_x = float(initial_pos[0] if initial_pos[0] > 0 else bounds.left)
|
||||
pos_y = float(initial_pos[1] if initial_pos[1] > 0 else bounds.top)
|
||||
direction = "+"
|
||||
|
||||
(size_x, size_y), _ = yield (bounds.left, bounds.top)
|
||||
|
||||
while True:
|
||||
range_x = bounds.width - size_x
|
||||
range_y = bounds.height - size_y
|
||||
|
||||
inc_x = range_x / period
|
||||
inc_y = range_y / period
|
||||
|
||||
if direction == "+":
|
||||
pos_x = pg.math.clamp(pos_x + inc_x, 0, range_x)
|
||||
pos_y = pg.math.clamp(pos_y + inc_y, 0, range_y)
|
||||
else:
|
||||
pos_x = pg.math.clamp(pos_x - inc_x, 0, range_x)
|
||||
pos_y = pg.math.clamp(pos_y - inc_y, 0, range_y)
|
||||
|
||||
if (inc_x and (pos_x > range_x - inc_x)) or (
|
||||
inc_y and (pos_y > range_y - inc_y)
|
||||
):
|
||||
direction = "-"
|
||||
elif (inc_x and (pos_x < inc_x)) or (inc_y and (pos_y < inc_y)):
|
||||
direction = "+"
|
||||
|
||||
(size_x, size_y), _ = yield (int(pos_x), int(pos_y))
|
||||
|
||||
|
||||
def transform_falling(
|
||||
bounds: pg.Rect,
|
||||
acceleration: float,
|
||||
initial_pos: Tuple[int, int],
|
||||
initial_velocity: float = 1.0,
|
||||
on_beat_reset: bool = False,
|
||||
) -> PositionGenerator:
|
||||
pos_x = float(initial_pos[0])
|
||||
pos_y = float(initial_pos[1])
|
||||
|
||||
(_, size_y), is_beat = yield (bounds.left, bounds.top)
|
||||
|
||||
velocity = initial_velocity
|
||||
|
||||
while True:
|
||||
range_y = bounds.height - size_y
|
||||
|
||||
pos_y += velocity
|
||||
velocity += acceleration
|
||||
|
||||
if (pos_y > range_y) or (on_beat_reset and is_beat):
|
||||
pos_y = initial_pos[1]
|
||||
velocity = initial_velocity
|
||||
|
||||
(_, size_y), is_beat = yield (int(pos_x), int(pos_y))
|
Loading…
Add table
Reference in a new issue