mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 03:30:13 +01:00
add input locking, fix more bugs
This commit is contained in:
@@ -14,6 +14,7 @@ from libs.utils import (
|
||||
force_dedicated_gpu,
|
||||
get_config,
|
||||
global_data,
|
||||
global_tex
|
||||
)
|
||||
from scenes.devtest import DevScreen
|
||||
from scenes.entry import EntryScreen
|
||||
@@ -68,7 +69,7 @@ def main():
|
||||
if global_data.config["video"]["target_fps"] != -1:
|
||||
ray.set_target_fps(global_data.config["video"]["target_fps"])
|
||||
ray.set_config_flags(ray.ConfigFlags.FLAG_MSAA_4X_HINT)
|
||||
ray.set_trace_log_level(ray.TraceLogLevel.LOG_INFO)
|
||||
ray.set_trace_log_level(ray.TraceLogLevel.LOG_WARNING)
|
||||
|
||||
camera = ray.Camera3D()
|
||||
camera.position = ray.Vector3(0.0, 0.0, 10.0) # Camera position
|
||||
@@ -78,9 +79,9 @@ def main():
|
||||
camera.projection = CAMERA_ORTHOGRAPHIC
|
||||
|
||||
ray.init_window(screen_width, screen_height, "PyTaiko")
|
||||
global_data.tex.load_screen_textures('global')
|
||||
global_data.tex.load_zip('chara', 'chara_0')
|
||||
global_data.tex.load_zip('chara', 'chara_1')
|
||||
global_tex.load_screen_textures('global')
|
||||
global_tex.load_zip('chara', 'chara_0')
|
||||
global_tex.load_zip('chara', 'chara_1')
|
||||
if global_data.config["video"]["borderless"]:
|
||||
ray.toggle_borderless_windowed()
|
||||
if global_data.config["video"]["fullscreen"]:
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import time
|
||||
from typing import Any, Optional
|
||||
|
||||
from libs.global_data import global_data
|
||||
|
||||
|
||||
def rounded(num: float) -> int:
|
||||
sign = 1 if (num >= 0) else -1
|
||||
@@ -15,7 +17,7 @@ def get_current_ms() -> int:
|
||||
|
||||
|
||||
class BaseAnimation():
|
||||
def __init__(self, duration: float, delay: float = 0.0, loop: bool = False) -> None:
|
||||
def __init__(self, duration: float, delay: float = 0.0, loop: bool = False, lock_input: bool = False) -> None:
|
||||
"""
|
||||
Initialize a base animation.
|
||||
|
||||
@@ -32,6 +34,7 @@ class BaseAnimation():
|
||||
self.attribute = 0
|
||||
self.is_started = False
|
||||
self.loop = loop
|
||||
self.lock_input = lock_input
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.__dict__)
|
||||
@@ -43,11 +46,15 @@ class BaseAnimation():
|
||||
"""Update the animation based on the current time."""
|
||||
if self.loop and self.is_finished:
|
||||
self.restart()
|
||||
if self.lock_input and self.is_finished:
|
||||
global_data.input_locked = False
|
||||
|
||||
def restart(self) -> None:
|
||||
self.start_ms = get_current_ms()
|
||||
self.is_finished = False
|
||||
self.delay = self.delay_saved
|
||||
if self.lock_input:
|
||||
global_data.input_locked = True
|
||||
|
||||
def start(self) -> None:
|
||||
self.is_started = True
|
||||
@@ -55,9 +62,13 @@ class BaseAnimation():
|
||||
|
||||
def pause(self):
|
||||
self.is_started = False
|
||||
if self.lock_input:
|
||||
global_data.input_locked = False
|
||||
|
||||
def unpause(self):
|
||||
self.is_started = True
|
||||
if self.lock_input:
|
||||
global_data.input_locked = True
|
||||
|
||||
def reset(self):
|
||||
self.restart()
|
||||
@@ -91,10 +102,10 @@ class BaseAnimation():
|
||||
|
||||
class FadeAnimation(BaseAnimation):
|
||||
def __init__(self, duration: float, initial_opacity: float = 1.0, loop: bool = False,
|
||||
final_opacity: float = 0.0, delay: float = 0.0,
|
||||
lock_input: bool = False, final_opacity: float = 0.0, delay: float = 0.0,
|
||||
ease_in: Optional[str] = None, ease_out: Optional[str] = None,
|
||||
reverse_delay: Optional[float] = None) -> None:
|
||||
super().__init__(duration, delay=delay, loop=loop)
|
||||
super().__init__(duration, delay=delay, loop=loop, lock_input=lock_input)
|
||||
self.initial_opacity = initial_opacity
|
||||
self.attribute = initial_opacity
|
||||
self.final_opacity = final_opacity
|
||||
@@ -139,10 +150,10 @@ class FadeAnimation(BaseAnimation):
|
||||
|
||||
class MoveAnimation(BaseAnimation):
|
||||
def __init__(self, duration: float, total_distance: int = 0, loop: bool = False,
|
||||
start_position: int = 0, delay: float = 0.0,
|
||||
lock_input: bool = False, start_position: int = 0, delay: float = 0.0,
|
||||
reverse_delay: Optional[float] = None,
|
||||
ease_in: Optional[str] = None, ease_out: Optional[str] = None) -> None:
|
||||
super().__init__(duration, delay=delay, loop=loop)
|
||||
super().__init__(duration, delay=delay, loop=loop, lock_input=lock_input)
|
||||
self.reverse_delay = reverse_delay
|
||||
self.reverse_delay_saved = reverse_delay
|
||||
self.total_distance = total_distance
|
||||
@@ -184,8 +195,8 @@ class MoveAnimation(BaseAnimation):
|
||||
|
||||
class TextureChangeAnimation(BaseAnimation):
|
||||
def __init__(self, duration: float, textures: list[tuple[float, float, int]],
|
||||
loop: bool = False, delay: float = 0.0) -> None:
|
||||
super().__init__(duration, loop=loop)
|
||||
loop: bool = False, lock_input: bool = False, delay: float = 0.0) -> None:
|
||||
super().__init__(duration, loop=loop, lock_input=lock_input)
|
||||
self.textures = textures
|
||||
self.delay = delay
|
||||
self.delay_saved = delay
|
||||
@@ -212,8 +223,8 @@ class TextureChangeAnimation(BaseAnimation):
|
||||
self.is_finished = True
|
||||
|
||||
class TextStretchAnimation(BaseAnimation):
|
||||
def __init__(self, duration: float, loop: bool = False,) -> None:
|
||||
super().__init__(duration, loop=loop)
|
||||
def __init__(self, duration: float, loop: bool = False, lock_input: bool = False) -> None:
|
||||
super().__init__(duration, loop=loop, lock_input=lock_input)
|
||||
def update(self, current_time_ms: float) -> None:
|
||||
if not self.is_started:
|
||||
return
|
||||
@@ -230,11 +241,11 @@ class TextStretchAnimation(BaseAnimation):
|
||||
|
||||
class TextureResizeAnimation(BaseAnimation):
|
||||
def __init__(self, duration: float, initial_size: float = 1.0,
|
||||
loop: bool = False,
|
||||
loop: bool = False, lock_input: bool = False,
|
||||
final_size: float = 0.0, delay: float = 0.0,
|
||||
reverse_delay: Optional[float] = None,
|
||||
ease_in: Optional[str] = None, ease_out: Optional[str] = None) -> None:
|
||||
super().__init__(duration, delay=delay, loop=loop)
|
||||
super().__init__(duration, delay=delay, loop=loop, lock_input=lock_input)
|
||||
self.initial_size = initial_size
|
||||
self.final_size = final_size
|
||||
self.reverse_delay = reverse_delay
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from libs.animation import Animation
|
||||
from libs.utils import global_data
|
||||
from libs.utils import global_tex
|
||||
|
||||
class Chara2D:
|
||||
def __init__(self, index: int, bpm: float, path: str = 'chara'):
|
||||
self.name = "chara_" + str(index)
|
||||
self.tex = global_data.tex
|
||||
self.tex = global_tex
|
||||
self.anims = dict()
|
||||
self.bpm = bpm
|
||||
self.current_anim = 'normal'
|
||||
|
||||
26
libs/global_data.py
Normal file
26
libs/global_data.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
@dataclass
|
||||
class Modifiers:
|
||||
auto: bool = False
|
||||
speed: float = 1.0
|
||||
display: bool = False
|
||||
inverse: bool = False
|
||||
random: int = 0
|
||||
|
||||
@dataclass
|
||||
class GlobalData:
|
||||
selected_song: Path = Path()
|
||||
songs_played: int = 0
|
||||
config: dict = field(default_factory=lambda: dict())
|
||||
song_hashes: dict[str, list[dict]] = field(default_factory=lambda: dict()) #Hash to path
|
||||
song_paths: dict[Path, str] = field(default_factory=lambda: dict()) #path to hash
|
||||
song_progress: float = 0.0
|
||||
total_songs: int = 0
|
||||
hit_sound: int = 0
|
||||
player_num: int = 1
|
||||
input_locked: bool = False
|
||||
modifiers: Modifiers = field(default_factory=lambda: Modifiers())
|
||||
|
||||
global_data = GlobalData()
|
||||
@@ -1,7 +1,7 @@
|
||||
from enum import Enum
|
||||
import pyray as ray
|
||||
|
||||
from libs.utils import OutlinedText, global_data
|
||||
from libs.utils import OutlinedText, global_tex
|
||||
|
||||
|
||||
class Nameplate:
|
||||
@@ -18,7 +18,7 @@ class Nameplate:
|
||||
self.name.unload()
|
||||
self.title.unload()
|
||||
def draw(self, x: int, y: int, fade: float = 1.0):
|
||||
tex = global_data.tex
|
||||
tex = global_tex
|
||||
tex.draw_texture('nameplate', 'shadow', x=x, y=y, fade=min(0.5, fade))
|
||||
if self.player_num == -1:
|
||||
frame = 2
|
||||
@@ -52,9 +52,9 @@ class Indicator:
|
||||
WAIT = 3
|
||||
def __init__(self, state: State):
|
||||
self.state = state
|
||||
self.don_fade = global_data.tex.get_animation(6)
|
||||
self.blue_arrow_move = global_data.tex.get_animation(7)
|
||||
self.blue_arrow_fade = global_data.tex.get_animation(8)
|
||||
self.don_fade = global_tex.get_animation(6)
|
||||
self.blue_arrow_move = global_tex.get_animation(7)
|
||||
self.blue_arrow_fade = global_tex.get_animation(8)
|
||||
|
||||
def update(self, current_time_ms: float):
|
||||
self.don_fade.update(current_time_ms)
|
||||
@@ -62,7 +62,7 @@ class Indicator:
|
||||
self.blue_arrow_fade.update(current_time_ms)
|
||||
|
||||
def draw(self, x: int, y: int, fade=1.0):
|
||||
tex = global_data.tex
|
||||
tex = global_tex
|
||||
tex.draw_texture('indicator', 'background', x=x, y=y, fade=fade)
|
||||
tex.draw_texture('indicator', 'text', frame=self.state.value, x=x, y=y, fade=fade)
|
||||
tex.draw_texture('indicator', 'drum_face', index=self.state.value, x=x, y=y, fade=fade)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import pyray as ray
|
||||
|
||||
from libs.utils import OutlinedText, global_data
|
||||
from libs.utils import OutlinedText, global_tex
|
||||
|
||||
|
||||
class Transition:
|
||||
def __init__(self, title: str, subtitle: str, is_second: bool = False) -> None:
|
||||
self.is_finished = False
|
||||
self.rainbow_up = global_data.tex.get_animation(0)
|
||||
self.mini_up = global_data.tex.get_animation(1)
|
||||
self.chara_down = global_data.tex.get_animation(2)
|
||||
self.song_info_fade = global_data.tex.get_animation(3)
|
||||
self.song_info_fade_out = global_data.tex.get_animation(4)
|
||||
self.rainbow_up = global_tex.get_animation(0)
|
||||
self.mini_up = global_tex.get_animation(1)
|
||||
self.chara_down = global_tex.get_animation(2)
|
||||
self.song_info_fade = global_tex.get_animation(3)
|
||||
self.song_info_fade_out = global_tex.get_animation(4)
|
||||
self.title = OutlinedText(title, 40, ray.WHITE, ray.BLACK, outline_thickness=5)
|
||||
self.subtitle = OutlinedText(subtitle, 30, ray.WHITE, ray.BLACK, outline_thickness=5)
|
||||
self.is_second = is_second
|
||||
@@ -38,7 +38,7 @@ class Transition:
|
||||
color_1 = ray.fade(ray.WHITE, self.song_info_fade_out.attribute)
|
||||
color_2 = ray.fade(ray.WHITE, min(0.70, self.song_info_fade_out.attribute))
|
||||
offset = 816 - self.rainbow_up.attribute
|
||||
global_data.tex.draw_texture('rainbow_transition', 'text_bg', y=-self.rainbow_up.attribute - offset, color=color_2)
|
||||
global_tex.draw_texture('rainbow_transition', 'text_bg', y=-self.rainbow_up.attribute - offset, color=color_2)
|
||||
|
||||
texture = self.title.texture
|
||||
y = 1176 - texture.height//2 - int(self.rainbow_up.attribute) - offset
|
||||
@@ -53,16 +53,16 @@ class Transition:
|
||||
total_offset = 0
|
||||
if self.is_second:
|
||||
total_offset = 816
|
||||
global_data.tex.draw_texture('rainbow_transition', 'rainbow_bg_bottom', y=-self.rainbow_up.attribute - total_offset)
|
||||
global_data.tex.draw_texture('rainbow_transition', 'rainbow_bg_top', y=-self.rainbow_up.attribute - total_offset)
|
||||
global_data.tex.draw_texture('rainbow_transition', 'rainbow_bg', y=-self.rainbow_up.attribute - total_offset)
|
||||
global_tex.draw_texture('rainbow_transition', 'rainbow_bg_bottom', y=-self.rainbow_up.attribute - total_offset)
|
||||
global_tex.draw_texture('rainbow_transition', 'rainbow_bg_top', y=-self.rainbow_up.attribute - total_offset)
|
||||
global_tex.draw_texture('rainbow_transition', 'rainbow_bg', y=-self.rainbow_up.attribute - total_offset)
|
||||
offset = self.chara_down.attribute
|
||||
chara_offset = 0
|
||||
if self.is_second:
|
||||
offset = self.chara_down.attribute - self.mini_up.attribute//3
|
||||
chara_offset = 408
|
||||
global_data.tex.draw_texture('rainbow_transition', 'chara_left', x=-self.mini_up.attribute//2 - chara_offset, y=-self.mini_up.attribute + offset - total_offset)
|
||||
global_data.tex.draw_texture('rainbow_transition', 'chara_right', x=self.mini_up.attribute//2 + chara_offset, y=-self.mini_up.attribute + offset - total_offset)
|
||||
global_data.tex.draw_texture('rainbow_transition', 'chara_center', y=-self.rainbow_up.attribute + offset - total_offset)
|
||||
global_tex.draw_texture('rainbow_transition', 'chara_left', x=-self.mini_up.attribute//2 - chara_offset, y=-self.mini_up.attribute + offset - total_offset)
|
||||
global_tex.draw_texture('rainbow_transition', 'chara_right', x=self.mini_up.attribute//2 + chara_offset, y=-self.mini_up.attribute + offset - total_offset)
|
||||
global_tex.draw_texture('rainbow_transition', 'chara_center', y=-self.rainbow_up.attribute + offset - total_offset)
|
||||
|
||||
self.draw_song_info()
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import ctypes
|
||||
import hashlib
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import zipfile
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from libs.global_data import global_data
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
@@ -89,6 +87,8 @@ def save_config(config: dict[str, Any]) -> None:
|
||||
tomlkit.dump(config, f)
|
||||
|
||||
def is_l_don_pressed() -> bool:
|
||||
if global_data.input_locked:
|
||||
return False
|
||||
keys = global_data.config["keys"]["left_don"]
|
||||
gamepad_buttons = global_data.config["gamepad"]["left_don"]
|
||||
for key in keys:
|
||||
@@ -111,6 +111,8 @@ def is_l_don_pressed() -> bool:
|
||||
return False
|
||||
|
||||
def is_r_don_pressed() -> bool:
|
||||
if global_data.input_locked:
|
||||
return False
|
||||
keys = global_data.config["keys"]["right_don"]
|
||||
gamepad_buttons = global_data.config["gamepad"]["right_don"]
|
||||
for key in keys:
|
||||
@@ -135,6 +137,8 @@ def is_r_don_pressed() -> bool:
|
||||
return False
|
||||
|
||||
def is_l_kat_pressed() -> bool:
|
||||
if global_data.input_locked:
|
||||
return False
|
||||
keys = global_data.config["keys"]["left_kat"]
|
||||
gamepad_buttons = global_data.config["gamepad"]["left_kat"]
|
||||
for key in keys:
|
||||
@@ -159,6 +163,8 @@ def is_l_kat_pressed() -> bool:
|
||||
return False
|
||||
|
||||
def is_r_kat_pressed() -> bool:
|
||||
if global_data.input_locked:
|
||||
return False
|
||||
keys = global_data.config["keys"]["right_kat"]
|
||||
gamepad_buttons = global_data.config["gamepad"]["right_kat"]
|
||||
for key in keys:
|
||||
@@ -182,14 +188,6 @@ def is_r_kat_pressed() -> bool:
|
||||
|
||||
return False
|
||||
|
||||
@dataclass
|
||||
class Modifiers:
|
||||
auto: bool = False
|
||||
speed: float = 1.0
|
||||
display: bool = False
|
||||
inverse: bool = False
|
||||
random: int = 0
|
||||
|
||||
@dataclass
|
||||
class SessionData:
|
||||
selected_difficulty: int = 0
|
||||
@@ -205,26 +203,11 @@ class SessionData:
|
||||
prev_score: int = 0
|
||||
|
||||
session_data = SessionData()
|
||||
global_tex = TextureWrapper()
|
||||
|
||||
def reset_session():
|
||||
return SessionData()
|
||||
|
||||
@dataclass
|
||||
class GlobalData:
|
||||
selected_song: Path = Path()
|
||||
tex: TextureWrapper = field(default_factory=lambda: TextureWrapper())
|
||||
songs_played: int = 0
|
||||
config: dict = field(default_factory=lambda: dict())
|
||||
song_hashes: dict[str, list[dict]] = field(default_factory=lambda: dict()) #Hash to path
|
||||
song_paths: dict[Path, str] = field(default_factory=lambda: dict()) #path to hash
|
||||
song_progress: float = 0.0
|
||||
total_songs: int = 0
|
||||
hit_sound: int = 0
|
||||
player_num: int = 1
|
||||
modifiers: Modifiers = field(default_factory=lambda: Modifiers())
|
||||
|
||||
global_data = GlobalData()
|
||||
|
||||
text_cache = set()
|
||||
if not Path('cache/image').exists():
|
||||
if not Path('cache').exists():
|
||||
|
||||
@@ -26,6 +26,7 @@ from libs.utils import (
|
||||
OutlinedText,
|
||||
get_current_ms,
|
||||
global_data,
|
||||
global_tex,
|
||||
is_l_don_pressed,
|
||||
is_l_kat_pressed,
|
||||
is_r_don_pressed,
|
||||
@@ -1412,7 +1413,7 @@ class SongInfo:
|
||||
class ResultTransition:
|
||||
def __init__(self, player_num: int):
|
||||
self.player_num = player_num
|
||||
self.move = global_data.tex.get_animation(5)
|
||||
self.move = global_tex.get_animation(5)
|
||||
self.move.reset()
|
||||
self.is_finished = False
|
||||
self.is_started = False
|
||||
@@ -1429,10 +1430,10 @@ class ResultTransition:
|
||||
x = 0
|
||||
screen_width = 1280
|
||||
while x < screen_width:
|
||||
global_data.tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter', frame=0, x=x, y=-720 + self.move.attribute)
|
||||
global_data.tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter', frame=0, x=x, y=720 - self.move.attribute)
|
||||
global_data.tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter_footer', x=x, y=-432 + self.move.attribute)
|
||||
global_data.tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter_footer', x=x, y=1008 - self.move.attribute)
|
||||
global_tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter', frame=0, x=x, y=-720 + self.move.attribute)
|
||||
global_tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter', frame=0, x=x, y=720 - self.move.attribute)
|
||||
global_tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter_footer', x=x, y=-432 + self.move.attribute)
|
||||
global_tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter_footer', x=x, y=1008 - self.move.attribute)
|
||||
x += 256
|
||||
|
||||
class Gauge:
|
||||
|
||||
@@ -10,12 +10,12 @@ import pyray as ray
|
||||
from libs.animation import Animation, MoveAnimation
|
||||
from libs.audio import audio
|
||||
from libs.chara_2d import Chara2D
|
||||
from libs.global_data import Modifiers
|
||||
from libs.global_objects import Nameplate, Indicator
|
||||
from libs.texture import tex
|
||||
from libs.tja import TJAParser, test_encodings
|
||||
from libs.transition import Transition
|
||||
from libs.utils import (
|
||||
Modifiers,
|
||||
OutlinedText,
|
||||
get_current_ms,
|
||||
global_data,
|
||||
@@ -288,7 +288,7 @@ class SongSelectScreen:
|
||||
if len(diffs) == 1:
|
||||
self.selected_difficulty = -1
|
||||
else:
|
||||
self.selected_difficulty = diffs[-2]
|
||||
self.selected_difficulty = diffs[-3]
|
||||
elif self.selected_difficulty == -1 or self.selected_difficulty == -2:
|
||||
self.diff_selector_move_2.start()
|
||||
self.prev_diff = self.selected_difficulty
|
||||
@@ -1208,6 +1208,8 @@ class NeiroSelector:
|
||||
self.curr_sound = audio.load_sound(Path("Sounds") / "hit_sounds" / str(self.selected_sound) / "don.ogg")
|
||||
|
||||
def move_left(self):
|
||||
if self.move.is_started and not self.move.is_finished:
|
||||
return
|
||||
self.selected_sound = (self.selected_sound - 1) % len(self.sounds)
|
||||
audio.unload_sound(self.curr_sound)
|
||||
self.load_sound()
|
||||
@@ -1221,6 +1223,8 @@ class NeiroSelector:
|
||||
audio.play_sound(self.curr_sound)
|
||||
|
||||
def move_right(self):
|
||||
if self.move.is_started and not self.move.is_finished:
|
||||
return
|
||||
self.selected_sound = (self.selected_sound + 1) % len(self.sounds)
|
||||
audio.unload_sound(self.curr_sound)
|
||||
self.load_sound()
|
||||
@@ -1234,6 +1238,8 @@ class NeiroSelector:
|
||||
audio.play_sound(self.curr_sound)
|
||||
|
||||
def confirm(self):
|
||||
if self.move.is_started and not self.move.is_finished:
|
||||
return
|
||||
if self.selected_sound == len(self.sounds):
|
||||
global_data.hit_sound = -1
|
||||
else:
|
||||
|
||||
@@ -88,6 +88,7 @@ class TitleScreen:
|
||||
|
||||
self.fade_out.update(get_current_ms())
|
||||
if self.fade_out.is_finished:
|
||||
self.fade_out.update(get_current_ms())
|
||||
return self.on_screen_end()
|
||||
|
||||
self.scene_manager()
|
||||
|
||||
Reference in New Issue
Block a user