mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 03:30:13 +01:00
Contributions are now open
This commit is contained in:
11
README.md
11
README.md
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
'''
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
139
scenes/game.py
139
scenes/game.py
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user