Contributions are now open

This commit is contained in:
Yonokid
2025-05-08 15:49:09 -04:00
parent bc08f24c9d
commit 209a98cd73
7 changed files with 227 additions and 261 deletions

View File

@@ -10,12 +10,13 @@ Download for OS of choice on releases page
How to run:
Windows:
```bash
PyTaiko.exe
```
Run PyTaiko.exe
```
MacOS/Linux:
```bash
PyTaiko.bin
```
Good luck, would suggest running with python directly
```
## Roadmap
@@ -68,4 +69,4 @@ I like it
## Contributing
I would highly suggest not contributing to this until sizeable progress has been made. The fabric of this code is ever changing and anything you write could disappear at any time
Contributions are now open. I don't have any particular contribution guidelines other than be mindful of what builtin functions already exist in this project (ie, for animations, videos, etc)

View File

@@ -3,113 +3,6 @@ from typing import Optional
from libs.utils import get_current_ms
class Animation:
def __init__(self, current_ms: float, duration: float, type: str):
self.type = type
self.start_ms = current_ms
self.attribute = 0
self.duration = duration
self.params = dict()
self.is_finished = False
def update(self, current_ms: float):
if self.type == 'move':
self.move(current_ms,
self.duration,
self.params['total_distance'],
self.params['start_position'],
delay=self.params.get('delay', 0.0),
ease_in=self.params.get('ease_in', None),
ease_out=self.params.get('ease_out', None))
elif self.type == 'texture_change':
self.texture_change(current_ms,
self.duration,
self.params['textures'])
elif self.type == 'text_stretch':
self.text_stretch(current_ms,
self.duration)
elif self.type == 'texture_resize':
self.texture_resize(current_ms,
self.duration,
initial_size=self.params.get('initial_size', 1.0),
final_size=self.params.get('final_size', 1.0),
delay=self.params.get('delay', 0.0))
if self.params.get('reverse', None) is not None and current_ms - self.start_ms >= self.duration + self.params.get('delay', 0.0):
self.texture_resize(current_ms,
self.duration,
final_size=self.params.get('initial_size', 1.0),
initial_size=self.params.get('final_size', 1.0),
delay=self.params.get('delay', 0.0) + self.duration)
def _ease_out_progress(self, progress: float, ease: str | None) -> float:
if ease == 'quadratic':
return progress * (2 - progress)
elif ease == 'cubic':
return 1 - pow(1 - progress, 3)
elif ease == 'exponential':
return 1 - pow(2, -10 * progress)
else:
return progress
def _ease_in_progress(self, progress: float, ease: str | None) -> float:
if ease == 'quadratic':
return progress * progress
elif ease == 'cubic':
return progress * progress * progress
elif ease == 'exponential':
return pow(2, 10 * (progress - 1))
else:
return progress
def move(self, current_ms: float, duration: float, total_distance: float, start_position: float, delay: float, ease_in: str | None, ease_out: str | None) -> None:
elapsed_time = current_ms - self.start_ms
if elapsed_time < delay:
self.attribute = start_position
elapsed_time -= delay
if elapsed_time <= duration:
if ease_in is not None:
progress = self._ease_in_progress(elapsed_time / duration, ease_in)
elif ease_out is not None:
progress = self._ease_out_progress(elapsed_time / duration, ease_out)
else:
progress = elapsed_time / duration
self.attribute = start_position + (total_distance * progress)
else:
self.attribute = start_position + total_distance
self.is_finished = True
def texture_change(self, current_ms: float, duration: float, textures: list[tuple[float, float, int]]) -> None:
elapsed_time = current_ms - self.start_ms
if elapsed_time <= duration:
for start, end, index in textures:
if start < elapsed_time <= end:
self.attribute = index
else:
self.is_finished = True
def text_stretch(self, current_ms: float, duration: float):
elapsed_time = current_ms - self.start_ms
if elapsed_time <= duration:
self.attribute = 2 + 5 * (elapsed_time // 25)
elif elapsed_time <= duration + 116:
frame_time = (elapsed_time - duration) // 16.57
self.attribute = 2 + 10 - (2 * (frame_time + 1))
else:
self.attribute = 0
self.is_finished = True
def texture_resize(self, current_ms: float, duration: float, initial_size: float, final_size: float, delay: float):
elapsed_time = current_ms - self.start_ms
if elapsed_time < delay:
self.attribute = initial_size
elapsed_time -= delay
if elapsed_time >= duration:
self.attribute = final_size
self.is_finished = True
elif elapsed_time < duration:
progress = elapsed_time / duration
self.attribute = initial_size + ((final_size - initial_size) * progress)
else:
self.attribute = final_size
self.is_finished = True
class BaseAnimation():
def __init__(self, duration: float, delay: float = 0.0):
"""
@@ -213,33 +106,134 @@ class MoveAnimation(BaseAnimation):
progress = self._apply_easing(progress, self.ease_in, self.ease_out)
self.attribute = self.start_position + (self.total_distance * progress)
class TextureChangeAnimation(BaseAnimation):
def __init__(self, duration: float, textures: list[tuple[float, float, int]]):
super().__init__(duration)
self.textures = textures
def update(self, current_time_ms: float):
elapsed_time = current_time_ms - self.start_ms
if elapsed_time <= self.duration:
for start, end, index in self.textures:
if start < elapsed_time <= end:
self.attribute = index
else:
self.is_finished = True
class Animation2:
class TextStretchAnimation(BaseAnimation):
def __init__(self, duration: float):
super().__init__(duration)
def update(self, current_time_ms: float):
elapsed_time = current_time_ms - self.start_ms
if elapsed_time <= self.duration:
self.attribute = 2 + 5 * (elapsed_time // 25)
elif elapsed_time <= self.duration + 116:
frame_time = (elapsed_time - self.duration) // 16.57
self.attribute = 2 + 10 - (2 * (frame_time + 1))
else:
self.attribute = 0
self.is_finished = True
class TextureResizeAnimation(BaseAnimation):
def __init__(self, duration: float, initial_size: float = 1.0,
final_size: float = 0.0, delay: float = 0.0,
reverse_delay: Optional[float] = None):
super().__init__(duration, delay)
self.initial_size = initial_size
self.final_size = final_size
self.reverse_delay = reverse_delay
def update(self, current_time_ms: float):
elapsed_time = current_time_ms - self.start_ms
if elapsed_time <= self.delay:
self.attribute = self.initial_size
elif elapsed_time >= self.delay + self.duration:
self.attribute = self.final_size
if self.reverse_delay is not None:
self.start_ms = current_time_ms
self.delay = self.reverse_delay
self.initial_size, self.final_size = self.final_size, self.initial_size
self.reverse_delay = None
else:
self.is_finished = True
else:
animation_time = elapsed_time - self.delay
progress = animation_time / self.duration
self.attribute = self.initial_size + ((self.final_size - self.initial_size) * progress)
class Animation:
"""Factory for creating different types of animations."""
@staticmethod
def create_fade(duration: float, **kwargs) -> FadeAnimation:
"""Create a fade animation."""
"""Create a fade animation.
Args:
duration: Length of the fade in milliseconds
delay: Time to wait before starting the fade
initial_opacity: Default is 1.0
final_opacity: Default is 0.0
reverse_delay: If provided, fade will play in reverse after this delay
ease_in: Control ease into the fade
ease_out: Control ease out of the fade
Easing options:
quadratic,
cubic,
exponential
"""
return FadeAnimation(duration, **kwargs)
@staticmethod
def create_move(duration: float, **kwargs) -> MoveAnimation:
"""Create a movement animation."""
"""Create a movement animation.
Args:
duration: Length of the move in milliseconds
start_position: The coordinates of the object before the move
total_distance: The distance travelled from the start to end position
delay: Time to wait before starting the move
ease_in: Control ease into the move
ease_out: Control ease out of the move
Easing options:
quadratic,
cubic,
exponential
"""
return MoveAnimation(duration, **kwargs)
'''
@staticmethod
def create_texture_change(duration: float, **kwargs) -> TextureChangeAnimation:
"""Create a texture change animation."""
"""Create a texture change animation
Args:
duration: Length of the change in milliseconds
textures: Passed in as a tuple of the starting millisecond, ending millisecond, and texture index
"""
return TextureChangeAnimation(duration, **kwargs)
@staticmethod
def create_text_stretch(duration: float) -> TextStretchAnimation:
"""Create a text stretch animation."""
"""Create a text stretch animation.
Args:
duration: Length of the stretch in milliseconds
"""
return TextStretchAnimation(duration)
@staticmethod
def create_texture_resize(duration: float, **kwargs) -> TextureResizeAnimation:
"""Create a texture resize animation."""
"""Create a texture resize animation.
Args:
duration: Length of the change in milliseconds
initial_size: Default is 1.0
final_size: Default is 0.0
delay: Time to wait before starting the resize
reverse_delay: If provided, resize will play in reverse after this delay
"""
return TextureResizeAnimation(duration, **kwargs)
'''

View File

@@ -95,11 +95,9 @@ def get_config() -> dict[str, Any]:
config_file = tomllib.load(f)
return config_file
def draw_scaled_texture(texture, x: int, y: int, scale: float, color: ray.Color) -> None:
width = texture.width
height = texture.height
src_rect = ray.Rectangle(0, 0, width, height)
dst_rect = ray.Rectangle(x, y, width*scale, height*scale)
def draw_scaled_texture(texture: ray.Texture, x: int, y: int, scale: float, color: ray.Color) -> None:
src_rect = ray.Rectangle(0, 0, texture.width, texture.height)
dst_rect = ray.Rectangle(x, y, texture.width*scale, texture.height*scale)
ray.draw_texture_pro(texture, src_rect, dst_rect, ray.Vector2(0, 0), 0, color)
@dataclass

View File

@@ -6,7 +6,10 @@ from libs.utils import get_current_ms
class VideoPlayer:
def __init__(self, path):
def __init__(self, path: str):
"""Initialize a video player instance. Audio must have the same name and an ogg extension.
Todo: extract audio from video directly
"""
self.is_finished_list = [False, False]
self.video_path = path
self.video = moviepy.VideoFileClip(path)
@@ -32,7 +35,7 @@ class VideoPlayer:
if time_played > ending_lenience:
self.is_finished_list[1] = True
def _load_frame(self, index):
def _load_frame(self, index: int):
"""Load a specific frame into the buffer"""
if index >= len(self.frame_timestamps) or index < 0:
return None
@@ -75,20 +78,26 @@ class VideoPlayer:
texture = self.frame_buffer.pop(ts)
ray.unload_texture(texture)
def is_started(self):
def is_started(self) -> bool:
"""Returns boolean value if the video has begun"""
return self.start_ms is not None
def start(self, current_ms):
def start(self, current_ms: float) -> None:
"""Start video playback at call time"""
self.start_ms = current_ms
for i in range(min(self.buffer_size, len(self.frame_timestamps))):
self._load_frame(i)
def is_finished(self):
def is_finished(self) -> bool:
"""Check if video is finished playing"""
return all(self.is_finished_list)
def set_volume(self, volume):
def set_volume(self, volume: float) -> None:
"""Set video volume, takes float value from 0.0 to 1.0"""
audio.set_music_volume(self.audio, volume)
def update(self):
"""Updates video playback, advancing frames and audio"""
self._audio_manager()
if self.frame_index >= len(self.frame_timestamps) - 1:
@@ -113,10 +122,12 @@ class VideoPlayer:
self._load_frame(current_index + i)
def draw(self):
"""Draw video frames to the raylib canvas"""
if self.current_frame is not None:
ray.draw_texture(self.current_frame, 0, 0, ray.WHITE)
def stop(self):
"""Stops the video, audio, and clears its buffer"""
for timestamp, texture in self.frame_buffer.items():
ray.unload_texture(texture)
self.frame_buffer.clear()

View File

@@ -5,7 +5,7 @@ from typing import Optional
import pyray as ray
from libs.animation import Animation, Animation2
from libs.animation import Animation
from libs.audio import audio
from libs.tja import Balloon, Drumroll, Note, TJAParser, calculate_base_score
from libs.utils import (
@@ -121,7 +121,7 @@ class GameScreen:
self.screen_init = True
self.init_tja(session_data.selected_song, session_data.selected_difficulty)
self.current_ms = get_current_ms() - self.start_ms
self.song_info = SongInfo(self.current_ms, self.tja.title, 'TEST')
self.song_info = SongInfo(self.tja.title, 'TEST')
self.result_transition = None
if self.movie is not None:
self.movie.start(get_current_ms())
@@ -150,7 +150,7 @@ class GameScreen:
elif len(self.player_1.play_notes) == 0:
session_data.result_score, session_data.result_good, session_data.result_ok, session_data.result_bad, session_data.result_max_combo, session_data.result_total_drumroll = self.player_1.get_result_score()
session_data.result_gauge_length = self.player_1.gauge.gauge_length
self.result_transition = ResultTransition(get_current_ms(), self.height)
self.result_transition = ResultTransition(self.height)
audio.play_sound(self.sound_result_transition)
def draw(self):
@@ -207,11 +207,11 @@ class Player:
self.balloon_anim: Optional[BalloonAnimation] = None
self.base_score_list: list[ScoreCounterAnimation] = []
self.combo_display = Combo(self.combo, get_current_ms())
self.score_counter = ScoreCounter(self.score, get_current_ms())
self.score_counter = ScoreCounter(self.score)
self.input_log: dict[float, tuple] = dict()
self.gauge = Gauge(get_current_ms(), self.difficulty, metadata[-1][self.difficulty][0])
self.gauge = Gauge(self.difficulty, metadata[-1][self.difficulty][0])
def get_result_score(self):
return self.score, self.good_count, self.ok_count, self.bad_count, self.total_drumroll, self.max_combo
@@ -326,7 +326,7 @@ class Player:
self.curr_drumroll_count += 1
self.total_drumroll += 1
self.score += 100
self.base_score_list.append(ScoreCounterAnimation(get_current_ms(), 100))
self.base_score_list.append(ScoreCounterAnimation(100))
if not isinstance(self.current_notes_draw[0], Drumroll):
return
self.current_notes_draw[0].color = max(0, 255 - (self.curr_drumroll_count * 10))
@@ -339,7 +339,7 @@ class Player:
self.curr_balloon_count += 1
self.total_drumroll += 1
self.score += 100
self.base_score_list.append(ScoreCounterAnimation(get_current_ms(), 100))
self.base_score_list.append(ScoreCounterAnimation(100))
if self.curr_balloon_count == note.count:
self.is_balloon = False
note.popped = True
@@ -377,22 +377,22 @@ class Player:
return
big = curr_note.type == 3 or curr_note.type == 4
if (curr_note.hit_ms - Player.TIMING_GOOD) + self.judge_offset <= game_screen.current_ms <= (curr_note.hit_ms + Player.TIMING_GOOD) + self.judge_offset:
self.draw_judge_list.append(Judgement(get_current_ms(), 'GOOD', big))
self.lane_hit_effect = LaneHitEffect(get_current_ms(), 'GOOD')
self.draw_judge_list.append(Judgement('GOOD', big))
self.lane_hit_effect = LaneHitEffect('GOOD')
self.good_count += 1
self.score += self.base_score
self.base_score_list.append(ScoreCounterAnimation(get_current_ms(), self.base_score))
self.base_score_list.append(ScoreCounterAnimation(self.base_score))
self.note_correct(game_screen, curr_note)
elif (curr_note.hit_ms - Player.TIMING_OK) + self.judge_offset <= game_screen.current_ms <= (curr_note.hit_ms + Player.TIMING_OK) + self.judge_offset:
self.draw_judge_list.append(Judgement(get_current_ms(), 'OK', big))
self.draw_judge_list.append(Judgement('OK', big))
self.ok_count += 1
self.score += 10 * math.floor(self.base_score / 2 / 10)
self.base_score_list.append(ScoreCounterAnimation(get_current_ms(), 10 * math.floor(self.base_score / 2 / 10)))
self.base_score_list.append(ScoreCounterAnimation(10 * math.floor(self.base_score / 2 / 10)))
self.note_correct(game_screen, curr_note)
elif (curr_note.hit_ms - Player.TIMING_BAD) + self.judge_offset <= game_screen.current_ms <= (curr_note.hit_ms + Player.TIMING_BAD) + self.judge_offset:
self.draw_judge_list.append(Judgement(get_current_ms(), 'BAD', big))
self.draw_judge_list.append(Judgement('BAD', big))
self.bad_count += 1
self.combo = 0
self.play_notes.popleft()
@@ -424,8 +424,8 @@ class Player:
for key in config["keys"]:
if ray.is_key_pressed(ord(key)):
hit_type = config["type"]
self.lane_hit_effect = LaneHitEffect(get_current_ms(), hit_type)
self.draw_drum_hit_list.append(DrumHitEffect(get_current_ms(), hit_type, config["side"]))
self.lane_hit_effect = LaneHitEffect(hit_type)
self.draw_drum_hit_list.append(DrumHitEffect(hit_type, config["side"]))
sound = game_screen.sound_don if hit_type == "DON" else game_screen.sound_kat
audio.play_sound(sound)
@@ -560,23 +560,17 @@ class Player:
anim.draw(game_screen)
class Judgement:
def __init__(self, game_screen, type: str, big: bool):
def __init__(self, type: str, big: bool):
self.type = type
self.big = big
self.is_finished = False
current_ms = get_current_ms()
self.fade_animation_1 = Animation2.create_fade(132, initial_opacity=0.5, delay=100)
self.fade_animation_1 = Animation.create_fade(132, initial_opacity=0.5, delay=100)
self.fade_animation_2 = Animation.create_fade(316 - 233.3, delay=233.3)
self.move_animation = Animation.create_move(83, total_distance=15, start_position=144)
self.texture_animation = Animation.create_texture_change(100, textures=[(33, 50, 1), (50, 83, 2), (83, 100, 3), (100, float('inf'), 4)])
self.fade_animation_2 = Animation2.create_fade(316 - 233.3, delay=233.3)
self.move_animation = Animation2.create_move(83, total_distance=15, start_position=144)
self.texture_animation = Animation(current_ms, 100, 'texture_change')
self.texture_animation.params['textures'] = [(33, 50, 1), (50, 83, 2), (83, 100, 3), (100, float('inf'), 4)]
def update(self, game_screen):
current_ms = get_current_ms()
def update(self, current_ms):
self.fade_animation_1.update(current_ms)
self.fade_animation_2.update(current_ms)
self.move_animation.update(current_ms)
@@ -610,10 +604,10 @@ class Judgement:
ray.draw_texture(textures_2[10], 370, int(y), color)
class LaneHitEffect:
def __init__(self, current_ms: float, type: str):
def __init__(self, type: str):
self.type = type
self.color = ray.fade(ray.WHITE, 0.5)
self.fade = Animation2.create_fade(150, delay=83, initial_opacity=0.5)
self.fade = Animation.create_fade(150, delay=83, initial_opacity=0.5)
self.is_finished = False
def update(self, current_ms: float):
@@ -632,12 +626,12 @@ class LaneHitEffect:
ray.draw_texture(textures[6], 328, 192, self.color)
class DrumHitEffect:
def __init__(self, current_ms: float, type: str, side: str):
def __init__(self, type: str, side: str):
self.type = type
self.side = side
self.color = ray.fade(ray.WHITE, 1)
self.is_finished = False
self.fade = Animation2.create_fade(100, delay=67)
self.fade = Animation.create_fade(100, delay=67)
def update(self, current_ms: float):
self.fade.update(current_ms)
@@ -753,15 +747,15 @@ class DrumrollCounter:
self.is_finished = False
self.total_duration = 1349
self.drumroll_count = 0
self.fade_animation = Animation2.create_fade(166, delay=self.total_duration - 166)
self.stretch_animation = Animation(current_ms, 0, 'text_stretch')
self.fade_animation = Animation.create_fade(166, delay=self.total_duration - 166)
self.stretch_animation = Animation.create_text_stretch(0)
def update_count(self, current_ms: float, count: int, elapsed_time: float):
def update_count(self, count: int, elapsed_time: float):
self.total_duration = elapsed_time + 1349
self.fade_animation.delay = self.total_duration - 166
if self.drumroll_count != count:
self.drumroll_count = count
self.stretch_animation = Animation(current_ms, 50, 'text_stretch')
self.stretch_animation = Animation.create_text_stretch(50)
def update(self, game_screen: GameScreen, current_ms: float, drumroll_count: int):
self.stretch_animation.update(current_ms)
@@ -769,7 +763,7 @@ class DrumrollCounter:
elapsed_time = current_ms - self.create_ms
if drumroll_count != 0:
self.update_count(current_ms, drumroll_count, elapsed_time)
self.update_count(drumroll_count, elapsed_time)
if self.fade_animation.is_finished:
self.is_finished = True
@@ -793,16 +787,16 @@ class BalloonAnimation:
self.balloon_count = 0
self.balloon_total = balloon_total
self.is_popped = False
self.fade_animation = Animation2.create_fade(166)
self.stretch_animation = Animation(current_ms, 0, 'text_stretch')
self.fade_animation = Animation.create_fade(166)
self.stretch_animation = Animation.create_text_stretch(0)
def update_count(self, current_ms: float, balloon_count: int):
def update_count(self, balloon_count: int):
if self.balloon_count != balloon_count:
self.balloon_count = balloon_count
self.stretch_animation = Animation(current_ms, 50, 'text_stretch')
self.stretch_animation = Animation.create_text_stretch(50)
def update(self, game_screen: GameScreen, current_ms: float, balloon_count: int, is_popped: bool):
self.update_count(current_ms, balloon_count)
self.update_count(balloon_count)
self.stretch_animation.update(current_ms)
self.is_popped = is_popped
@@ -837,7 +831,7 @@ class BalloonAnimation:
class Combo:
def __init__(self, combo: int, current_ms: float):
self.combo = combo
self.stretch_animation = Animation(current_ms, 0, 'text_stretch')
self.stretch_animation = Animation.create_text_stretch(0)
self.color = [ray.fade(ray.WHITE, 1), ray.fade(ray.WHITE, 1), ray.fade(ray.WHITE, 1)]
self.glimmer_dict = {0: 0, 1: 0, 2: 0}
self.total_time = 250
@@ -851,7 +845,7 @@ class Combo:
def update_count(self, current_ms: float, combo: int):
if self.combo != combo:
self.combo = combo
self.stretch_animation = Animation(current_ms, 50, 'text_stretch')
self.stretch_animation = Animation.create_text_stretch(50)
def update(self, game_screen: GameScreen, current_ms: float, combo: int):
self.update_count(current_ms, combo)
@@ -900,15 +894,14 @@ class Combo:
ray.draw_texture(game_screen.texture_combo_glimmer, x + (i * 30), y + self.glimmer_dict[j], self.color[j])
class ScoreCounter:
def __init__(self, score: int, current_ms: float):
def __init__(self, score: int):
self.score = score
self.create_ms = current_ms
self.stretch_animation = Animation(current_ms, 0, 'text_stretch')
self.stretch_animation = Animation.create_text_stretch(0)
def update_count(self, current_ms: float, score: int):
if self.score != score:
self.score = score
self.stretch_animation = Animation(current_ms, 50, 'text_stretch')
self.stretch_animation = Animation.create_text_stretch(50)
def update(self, current_ms: float, score: int):
self.update_count(current_ms, score)
@@ -927,14 +920,14 @@ class ScoreCounter:
ray.draw_texture_pro(game_screen.textures['lane_obi'][int(counter[i])+4], source_rect, dest_rect, ray.Vector2(0,0), 0, ray.WHITE)
class ScoreCounterAnimation:
def __init__(self, current_ms: float, counter: int):
def __init__(self, counter: int):
self.counter = counter
self.fade_animation_1 = Animation2.create_fade(50, initial_opacity=0.0, final_opacity=1.0)
self.move_animation_1 = Animation2.create_move(80, total_distance=-20, start_position=175)
self.fade_animation_2 = Animation2.create_fade(80, delay=366.74)
self.move_animation_2 = Animation2.create_move(66, total_distance=5, start_position=145, delay=80)
self.move_animation_3 = Animation2.create_move(66, delay=279.36, total_distance=-2, start_position=146)
self.move_animation_4 = Animation2.create_move(80, delay=366.74, total_distance=10, start_position=148)
self.fade_animation_1 = Animation.create_fade(50, initial_opacity=0.0, final_opacity=1.0)
self.move_animation_1 = Animation.create_move(80, total_distance=-20, start_position=175)
self.fade_animation_2 = Animation.create_fade(80, delay=366.74)
self.move_animation_2 = Animation.create_move(66, total_distance=5, start_position=145, delay=80)
self.move_animation_3 = Animation.create_move(66, delay=279.36, total_distance=-2, start_position=146)
self.move_animation_4 = Animation.create_move(80, delay=366.74, total_distance=10, start_position=148)
self.color = ray.fade(ray.Color(254, 102, 0, 255), 1.0)
self.is_finished = False
@@ -984,9 +977,9 @@ class SongInfo:
FADE_DURATION = 366
DISPLAY_DURATION = 1666
def __init__(self, current_ms: float, song_name: str, genre: str):
self.fade_in = Animation2.create_fade(self.FADE_DURATION, initial_opacity=0.0, final_opacity=1.0)
self.fade_out = Animation2.create_fade(self.FADE_DURATION, delay=self.FADE_DURATION + self.DISPLAY_DURATION)
def __init__(self, song_name: str, genre: str):
self.fade_in = Animation.create_fade(self.FADE_DURATION, initial_opacity=0.0, final_opacity=1.0)
self.fade_out = Animation.create_fade(self.FADE_DURATION, delay=self.FADE_DURATION + self.DISPLAY_DURATION)
self.song_name = song_name
self.genre = genre
@@ -1014,11 +1007,11 @@ class SongInfo:
self.song_name_fade = ray.fade(ray.WHITE, 1 - self.fade_out.attribute)
if self.fade_out.is_finished:
self._reset_animations(current_ms)
self._reset_animations()
def _reset_animations(self, current_ms: float):
self.fade_in = Animation2.create_fade(self.FADE_DURATION, initial_opacity=0.0, final_opacity=1.0)
self.fade_out = Animation2.create_fade(self.FADE_DURATION, delay=self.FADE_DURATION + self.DISPLAY_DURATION)
def _reset_animations(self):
self.fade_in = Animation.create_fade(self.FADE_DURATION, initial_opacity=0.0, final_opacity=1.0)
self.fade_out = Animation.create_fade(self.FADE_DURATION, delay=self.FADE_DURATION + self.DISPLAY_DURATION)
def draw(self, game_screen: GameScreen):
song_texture_index = (global_data.songs_played % 4) + 8
@@ -1033,8 +1026,8 @@ class SongInfo:
self.song_title.draw(text_x, text_y, self.song_name_fade)
class ResultTransition:
def __init__(self, current_ms: float, screen_height: int):
self.move = Animation2.create_move(983.33, start_position=0, total_distance=screen_height//2, ease_out='quadratic')
def __init__(self, screen_height: int):
self.move = Animation.create_move(983.33, start_position=0, total_distance=screen_height//2, ease_out='quadratic')
self.is_finished = False
@@ -1057,7 +1050,7 @@ class ResultTransition:
x += texture_2.width
class Gauge:
def __init__(self, current_ms: float, difficulty: int, level: int):
def __init__(self, difficulty: int, level: int):
self.gauge_length = 0
self.difficulty = min(3, difficulty)
self.clear_start = [0, 0, 68, 68]
@@ -1110,18 +1103,6 @@ class Gauge:
self.rainbow_fade_in = None
self.rainbow_animation = None
def _create_rainbow_anim(self, current_ms):
anim = Animation(current_ms, (16.67*8) * 3, 'texture_change')
anim.params['textures'] = []
for i in range(8):
anim.params['textures'].append(((16.67* 3)*i, (16.67 * 3)*(i+1), i))
anim.params['textures'] = tuple(anim.params['textures'])
return anim
def _create_anim(self, current_ms: float, init: float, final: float):
anim = Animation2.create_fade(450, initial_opacity=init, final_opacity=final)
return anim
def update(self, current_ms: float, good_count: int, ok_count: int, bad_count: int, total_notes: int):
gauge_length = int(((good_count +
(ok_count * self.table[self.difficulty][self.level]["ok_multiplier"] +
@@ -1129,9 +1110,9 @@ class Gauge:
previous_length = self.gauge_length
self.gauge_length = min(87, gauge_length)
if self.gauge_length == 87 and self.rainbow_fade_in is None:
self.rainbow_fade_in = self._create_anim(current_ms, 0.0, 1.0)
self.rainbow_fade_in = Animation.create_fade(450, initial_opacity=0.0, final_opacity=1.0)
if self.gauge_length > previous_length:
self.gauge_update_anim = self._create_anim(current_ms, 1.0, 0.0)
self.gauge_update_anim = Animation.create_fade(450)
if self.gauge_update_anim is not None:
self.gauge_update_anim.update(current_ms)
@@ -1142,7 +1123,7 @@ class Gauge:
self.rainbow_fade_in.update(current_ms)
if self.rainbow_animation is None:
self.rainbow_animation = self._create_rainbow_anim(current_ms)
self.rainbow_animation = Animation.create_texture_change((16.67*8) * 3, textures=[((16.67 * 3) * i, (16.67 * 3) * (i + 1), i) for i in range(8)])
else:
self.rainbow_animation.update(current_ms)
if self.rainbow_animation.is_finished or self.gauge_length < 87:

View File

@@ -3,7 +3,7 @@ from pathlib import Path
import pyray as ray
from libs import utils
from libs.animation import Animation, Animation2
from libs.animation import Animation
from libs.audio import audio
from libs.utils import (
OutlinedText,
@@ -178,7 +178,7 @@ class ResultScreen:
class FadeIn:
def __init__(self, current_ms: float):
self.fadein = Animation2.create_fade(450, initial_opacity=1.0, final_opacity=0.0, delay=100)
self.fadein = Animation.create_fade(450, initial_opacity=1.0, final_opacity=0.0, delay=100)
self.fade = ray.fade(ray.WHITE, self.fadein.attribute)
self.is_finished = False
@@ -235,18 +235,15 @@ class Gauge:
def __init__(self, current_ms: float, gauge_length):
self.gauge_length = gauge_length
self.rainbow_animation = None
self.gauge_fade_in = Animation2.create_fade(366, initial_opacity=0.0, final_opacity=1.0)
self.gauge_fade_in = Animation.create_fade(366, initial_opacity=0.0, final_opacity=1.0)
self.is_finished = self.gauge_fade_in.is_finished
def _create_rainbow_anim(self, current_ms):
anim = Animation(current_ms, (16.67*8) * 3, 'texture_change')
anim.params['textures'] = []
for i in range(8):
anim.params['textures'].append(((16.67* 3)*i, (16.67 * 3)*(i+1), i))
anim = Animation.create_texture_change((16.67*8) * 3, textures=[((16.67 * 3) * i, (16.67 * 3) * (i + 1), i) for i in range(8)])
return anim
def _create_anim(self, current_ms: float, init: float, final: float):
anim = Animation2.create_fade(450, initial_opacity=init, final_opacity=final)
anim = Animation.create_fade(450, initial_opacity=init, final_opacity=final)
return anim
def update(self, current_ms: float):

View File

@@ -3,7 +3,7 @@ from pathlib import Path
import pyray as ray
from libs.animation import Animation, Animation2
from libs.animation import Animation
from libs.audio import audio
from libs.utils import (
get_config,
@@ -46,6 +46,7 @@ class TitleScreen:
if not self.screen_init:
self.screen_init = True
self.load_textures()
self.scene = 'Opening Video'
self.op_video = VideoPlayer(random.choice(self.op_video_list))
self.attract_video = VideoPlayer(random.choice(self.attract_video_list))
@@ -107,25 +108,17 @@ class TitleScreen:
elif self.scene == 'Attract Video':
self.attract_video.draw()
ray.draw_text(f"Scene: {self.scene}", 20, 40, 20, ray.BLUE)
class WarningScreen:
class X:
DELAY = 4250
def __init__(self, current_ms: float):
self.resize = Animation(current_ms, 166.67, 'texture_resize')
self.resize.params['initial_size'] = 1.0
self.resize.params['final_size'] = 1.5
self.resize.params['delay'] = self.DELAY
self.resize.params['reverse'] = 0
self.fadein = Animation2.create_fade(166.67, delay=self.DELAY, initial_opacity=0.0, final_opacity=1.0, reverse_delay=166.67)
self.fadein_2 = Animation2.create_fade(166.67, delay=self.DELAY + self.fadein.duration, initial_opacity=0.0, final_opacity=1.0)
def __init__(self):
self.resize = Animation.create_texture_resize(166.67, initial_size=1.0, final_size=1.5, delay=self.DELAY, reverse_delay=0)
self.fadein = Animation.create_fade(166.67, delay=self.DELAY, initial_opacity=0.0, final_opacity=1.0, reverse_delay=166.67)
self.fadein_2 = Animation.create_fade(166.67, delay=self.DELAY + self.fadein.duration, initial_opacity=0.0, final_opacity=1.0)
self.sound_played = False
def update(self, current_ms: float, sound, elapsed_time):
self.fadein.update(current_ms)
self.fadein_2.update(current_ms)
self.resize.update(current_ms)
@@ -136,21 +129,16 @@ class WarningScreen:
def draw(self, texture):
scale = self.resize.attribute
width = texture.width
height = texture.height
x_x = 150 + (width//2) - ((width * scale)//2)
x_y = 200 + (height//2) - ((height * scale)//2)
x_source = ray.Rectangle(0, 0, width, height)
x_dest = ray.Rectangle(x_x, x_y, width*scale, height*scale)
x_x = 150 + (texture.width//2) - ((texture.width * scale)//2)
x_y = 200 + (texture.height//2) - ((texture.height * scale)//2)
x_source = ray.Rectangle(0, 0, texture.width, texture.height)
x_dest = ray.Rectangle(x_x, x_y, texture.width*scale, texture.height*scale)
ray.draw_texture_pro(texture, x_source, x_dest, ray.Vector2(0,0), 0, ray.fade(ray.WHITE, self.fadein.attribute))
class BachiHit:
def __init__(self, current_ms: float):
self.resize = Animation(current_ms, 233.34, 'texture_resize')
self.resize.params['initial_size'] = 0.5
self.resize.params['final_size'] = 1.5
self.fadein = Animation2.create_fade(116.67, initial_opacity=0.0, final_opacity=1.0, reverse_delay=0)
def __init__(self):
self.resize = Animation.create_texture_resize(233.34, initial_size=0.5, final_size=1.5)
self.fadein = Animation.create_fade(116.67, initial_opacity=0.0, final_opacity=1.0, reverse_delay=0)
self.sound_played = False
@@ -165,19 +153,17 @@ class WarningScreen:
def draw(self, texture):
scale = self.resize.attribute
width = texture.width
height = texture.height
hit_x = 350 + (width//2) - ((width * scale)//2)
hit_y = 225 + (height//2) - ((height * scale)//2)
hit_source = ray.Rectangle(0, 0, width, height)
hit_dest = ray.Rectangle(hit_x, hit_y, width*scale, height*scale)
hit_x = 350 + (texture.width//2) - ((texture.width * scale)//2)
hit_y = 225 + (texture.height//2) - ((texture.height * scale)//2)
hit_source = ray.Rectangle(0, 0, texture.width, texture.height)
hit_dest = ray.Rectangle(hit_x, hit_y, texture.width*scale, texture.height*scale)
ray.draw_texture_pro(texture, hit_source, hit_dest, ray.Vector2(0,0), 0, ray.fade(ray.WHITE, self.fadein.attribute))
class Characters:
def __init__(self, current_ms: float, start_ms: float):
self.start_ms = start_ms
self.current_ms = current_ms
self.shadow_fade = Animation2.create_fade(50, delay=16.67, initial_opacity=0.75)
self.shadow_fade = Animation.create_fade(50, delay=16.67, initial_opacity=0.75)
self.animation_sequence = [(300.00, 5, 4), (183.33, 6, 4), (166.67, 7, 4), (166.67, 8, 9), (166.67, 11, 9), (166.67, 12, 9), (166.67, 13, 9),
(166.67, 5, 4), (150.00, 5, 4), (133.34, 6, 4), (133.34, 7, 4), (133.34, 8, 9), (133.34, 11, 9), (133.34, 12, 9), (133.34, 13, 9),
@@ -228,15 +214,15 @@ class WarningScreen:
ray.draw_texture(textures['keikoku'][19], 350, y+135, ray.WHITE)
class Board:
def __init__(self, current_ms: float, screen_width, screen_height, texture):
def __init__(self, screen_width, screen_height, texture):
#Move warning board down from top of screen
self.move_down = Animation2.create_move(266.67, total_distance=screen_height + ((screen_height - texture.height)//2) + 20, start_position=-720)
self.move_down = Animation.create_move(266.67, total_distance=screen_height + ((screen_height - texture.height)//2) + 20, start_position=-720)
#Move warning board up a little bit
self.move_up = Animation2.create_move(116.67, start_position=92 + 20, delay=self.move_down.duration, total_distance =-30)
self.move_up = Animation.create_move(116.67, start_position=92 + 20, delay=self.move_down.duration, total_distance =-30)
#And finally into its correct position
self.move_center = Animation2.create_move(116.67, start_position=82, delay=self.move_down.duration + self.move_up.duration, total_distance=10)
self.move_center = Animation.create_move(116.67, start_position=82, delay=self.move_down.duration + self.move_up.duration, total_distance=10)
self.y_pos = 0
def update(self, current_ms):
@@ -257,14 +243,12 @@ class WarningScreen:
def __init__(self, current_ms: float, title_screen: TitleScreen):
self.start_ms = current_ms
self.fade_in = Animation2.create_fade(300, delay=266.67, initial_opacity=0.0, final_opacity=1.0)
self.fade_in = Animation.create_fade(300, delay=266.67, initial_opacity=0.0, final_opacity=1.0)
self.fade_out = Animation.create_fade(500, delay=1000, initial_opacity=0.0, final_opacity=1.0)
#Fade to black
self.fade_out = Animation2.create_fade(500, delay=1000, initial_opacity=0.0, final_opacity=1.0)
self.board = self.Board(current_ms, title_screen.width, title_screen.height, title_screen.textures['keikoku'][1])
self.warning_x = self.X(current_ms)
self.warning_bachi_hit = self.BachiHit(current_ms)
self.board = self.Board(title_screen.width, title_screen.height, title_screen.textures['keikoku'][1])
self.warning_x = self.X()
self.warning_bachi_hit = self.BachiHit()
self.characters = self.Characters(current_ms, self.start_ms)
self.source_rect = ray.Rectangle(0, 0, title_screen.texture_black.width, title_screen.texture_black.height)