2023-02-17 02:06:34 +01:00
|
|
|
from dataclasses import dataclass
|
|
|
|
import math
|
|
|
|
import random
|
2023-02-19 16:02:49 +01:00
|
|
|
from typing import Generator, Literal, Tuple
|
2023-02-15 21:08:47 +01:00
|
|
|
import pygame as pg
|
|
|
|
|
|
|
|
|
2023-02-18 22:51:52 +01:00
|
|
|
def copy_color(source: pg.Color) -> pg.Color:
|
|
|
|
return pg.Color(source.r, source.g, source.b, source.a)
|
|
|
|
|
|
|
|
|
2023-02-17 02:06:34 +01:00
|
|
|
@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)
|
|
|
|
|
|
|
|
|
2023-02-18 23:17:03 +01:00
|
|
|
def color_wheel(hue=0, increase=1) -> Generator[pg.Color, None, None]:
|
2023-02-18 22:51:52 +01:00
|
|
|
color = copy_color(Colors.Red)
|
2023-02-15 22:37:45 +01:00
|
|
|
h, s, l, a = color.hsla
|
2023-02-18 22:51:52 +01:00
|
|
|
h = hue
|
2023-02-15 22:37:45 +01:00
|
|
|
|
|
|
|
while True:
|
2023-02-18 22:51:52 +01:00
|
|
|
color.hsla = h, s, l, a
|
2023-02-15 22:37:45 +01:00
|
|
|
yield color
|
|
|
|
h = (h + increase) % 360
|
|
|
|
|
|
|
|
|
2023-02-18 23:17:03 +01:00
|
|
|
def color_randomize() -> Generator[pg.Color, None, None]:
|
2023-02-18 22:51:52 +01:00
|
|
|
color = copy_color(Colors.Red)
|
2023-02-17 02:06:34 +01:00
|
|
|
h, s, l, a = color.hsla
|
2023-02-20 01:59:55 +01:00
|
|
|
color.hsla = random.randrange(0, 360 // 5) * 5, s, l, a
|
2023-02-17 02:06:34 +01:00
|
|
|
|
|
|
|
while True:
|
|
|
|
yield color
|
2023-02-20 01:59:55 +01:00
|
|
|
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
|
2023-02-17 02:06:34 +01:00
|
|
|
|
|
|
|
|
2023-02-19 16:02:49 +01:00
|
|
|
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))
|
|
|
|
|
|
|
|
|
2023-02-17 02:06:34 +01:00
|
|
|
def transform_bounce(
|
|
|
|
bounds: pg.Rect,
|
2023-02-19 16:02:58 +01:00
|
|
|
velocity: Tuple[float, float],
|
2023-02-19 02:01:28 +01:00
|
|
|
x_factor: Tuple[float, float],
|
|
|
|
y_factor: Tuple[float, float],
|
2023-02-18 23:17:03 +01:00
|
|
|
) -> Generator[Tuple[int, int], Tuple[int, int], None]:
|
2023-02-17 02:06:34 +01:00
|
|
|
min_velocity = velocity[0]
|
|
|
|
max_velocity = velocity[1]
|
2023-02-19 16:02:58 +01:00
|
|
|
current_velocity = random.uniform(min_velocity, max_velocity)
|
2023-02-19 02:01:28 +01:00
|
|
|
phase = random.uniform(0, 360)
|
2023-02-18 23:17:03 +01:00
|
|
|
current_x_factor = random.uniform(x_factor[0], x_factor[1])
|
|
|
|
current_y_factor = random.uniform(y_factor[0], y_factor[1])
|
2023-02-17 02:06:34 +01:00
|
|
|
|
|
|
|
size_x, size_y = yield (bounds.centerx, bounds.centery)
|
|
|
|
while True:
|
2023-02-18 23:17:03 +01:00
|
|
|
pos_x = int(
|
2023-02-19 02:01:28 +01:00
|
|
|
math.cos(current_x_factor * phase) * (bounds.width - size_x) // 2
|
2023-02-18 23:17:03 +01:00
|
|
|
+ bounds.centerx
|
2023-02-17 02:06:34 +01:00
|
|
|
)
|
2023-02-18 23:17:03 +01:00
|
|
|
pos_y = int(
|
2023-02-19 02:01:28 +01:00
|
|
|
math.sin(current_y_factor * phase) * (bounds.height - size_y) // 2
|
2023-02-18 23:17:03 +01:00
|
|
|
+ bounds.centery
|
2023-02-17 02:06:34 +01:00
|
|
|
)
|
|
|
|
|
2023-02-19 02:01:28 +01:00
|
|
|
phase += current_velocity / 180 * math.pi
|
2023-02-20 01:59:55 +01:00
|
|
|
# current_velocity = random.uniform(min_velocity, max_velocity)
|
2023-02-17 02:06:34 +01:00
|
|
|
size_x, size_y = yield (pos_x, pos_y)
|
|
|
|
|
|
|
|
|
2023-02-19 16:02:28 +01:00
|
|
|
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))
|
|
|
|
|
|
|
|
|
2023-02-20 01:59:55 +01:00
|
|
|
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))
|
|
|
|
|
|
|
|
|
2023-02-15 21:08:47 +01:00
|
|
|
class Effect(pg.sprite.Sprite):
|
|
|
|
def __init__(
|
|
|
|
self, image: pg.Surface, rect: pg.Rect, *groups: pg.sprite.Group
|
|
|
|
) -> None:
|
|
|
|
super().__init__(*groups)
|
|
|
|
self.rect = rect
|
|
|
|
self.image = image
|
|
|
|
|
|
|
|
def draw(self, surface: pg.Surface):
|
|
|
|
surface.blit(self.image, self.rect)
|