pybeamshow/util/transform.py

122 lines
3.3 KiB
Python
Raw Normal View History

2023-02-22 22:55:11 +01:00
import math
import random
2023-02-23 00:19:20 +01:00
from typing import Generator, Optional, Tuple
2023-02-22 22:55:11 +01:00
import pygame as pg
2023-02-24 18:21:21 +01:00
from util import XYCoord
2023-02-23 00:19:20 +01:00
2023-02-24 18:21:21 +01:00
PositionGenerator = Generator[XYCoord, Tuple[XYCoord, Optional[bool]], None]
2023-02-23 00:19:20 +01:00
2023-02-24 18:21:21 +01:00
def transform_static(position: XYCoord) -> PositionGenerator:
2023-02-23 00:19:20 +01:00
while True:
_ = yield (position)
2023-02-22 22:55:11 +01:00
def transform_bounce(
bounds: pg.Rect,
velocity: Tuple[float, float],
x_factor: Tuple[float, float],
y_factor: Tuple[float, float],
2023-02-23 00:19:20 +01:00
on_beat_random_phase: int = 0,
2023-02-23 01:56:05 +01:00
on_beat_phase: int = 0,
2023-02-22 22:55:11 +01:00
) -> 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])
2023-02-22 23:36:08 +01:00
pos_x = bounds.centerx
pos_y = bounds.centery
2023-02-22 22:55:11 +01:00
while True:
2023-02-22 23:36:08 +01:00
(size_x, size_y), is_beat = yield (pos_x, pos_y)
2023-02-22 22:55:11 +01:00
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
)
2023-02-23 00:19:20 +01:00
inc = current_velocity
2023-02-22 22:55:11 +01:00
if on_beat_random_phase and is_beat:
2023-02-23 00:19:20 +01:00
inc += random.randrange(0, on_beat_random_phase)
2023-02-23 01:56:05 +01:00
if on_beat_phase and is_beat:
inc += on_beat_phase
2023-02-23 00:19:20 +01:00
phase += inc / 180 * math.pi
2023-02-22 22:55:11 +01:00
def transform_oscillate(
bounds: pg.Rect,
period: int,
2023-02-24 18:58:51 +01:00
initial_pos: XYCoord = (0, 0),
auto_period: int = 0,
2023-02-22 22:55:11 +01:00
) -> PositionGenerator:
2023-02-24 18:58:51 +01:00
pos_x = float(initial_pos[0])
pos_y = float(initial_pos[1])
2023-02-22 22:55:11 +01:00
direction = "+"
2023-02-24 18:58:51 +01:00
last_period = 0
2023-02-22 22:55:11 +01:00
while True:
2023-02-24 18:58:51 +01:00
(size_x, size_y), is_beat = yield (
int(pos_x + bounds.left),
int(pos_y + bounds.top),
)
2023-02-22 23:36:08 +01:00
2023-02-22 22:55:11 +01:00
range_x = bounds.width - size_x
range_y = bounds.height - size_y
2023-02-24 18:58:51 +01:00
if auto_period:
if is_beat:
period = last_period * auto_period
last_period = 0
else:
last_period += 1
2023-02-22 22:55:11 +01:00
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 = "+"
def transform_falling(
bounds: pg.Rect,
acceleration: float,
2023-02-24 18:21:21 +01:00
initial_pos: XYCoord,
2023-02-22 22:55:11 +01:00
initial_velocity: float = 1.0,
on_beat_reset: bool = False,
) -> PositionGenerator:
pos_x = float(initial_pos[0])
pos_y = float(initial_pos[1])
velocity = initial_velocity
2023-02-22 23:36:08 +01:00
pos_x = bounds.left
pos_y = bounds.top
2023-02-22 22:55:11 +01:00
while True:
2023-02-22 23:36:08 +01:00
(_, size_y), is_beat = yield (int(pos_x), int(pos_y))
2023-02-22 22:55:11 +01:00
range_y = bounds.height - size_y
pos_y += velocity
velocity += acceleration
2023-02-23 01:56:05 +01:00
if (not on_beat_reset and (pos_y > range_y)) or (on_beat_reset and is_beat):
2023-02-22 22:55:11 +01:00
pos_y = initial_pos[1]
velocity = initial_velocity