more graphics wrapper updates

This commit is contained in:
Yonokid
2025-08-11 15:03:40 -04:00
parent 60fab76c5a
commit 9b5abaa644
13 changed files with 231 additions and 320 deletions

View File

@@ -24,6 +24,35 @@ Linux:
``` ```
Run PyTaiko.bin for Debian based systems, otherwise run python Run PyTaiko.bin for Debian based systems, otherwise run python
``` ```
Nix OS:
Use the provided shell.nix code and run with python:
```
{ pkgs ? import <nixpkgs> {} }:
(pkgs.buildFHSEnv {
name = "PyTaiko-env";
targetPkgs = pkgs: (with pkgs; [
python3Full
gcc
libGL
uv
patchelf
portaudio
zlib
python312Packages.pyaudio
python312Packages.nuitka
python312Packages.numpy
alsa-lib
xorg.libX11 xorg.libxcb xorg.libXcomposite
xorg.libXdamage xorg.libXext xorg.libXfixes
xorg.libXrender xorg.libxshmfence xorg.libXtst
xorg.libXi
xorg.xcbutilkeysyms
]);
runScript = "bash";
}).env
```
## Roadmap ## Roadmap
@@ -33,9 +62,12 @@ Ask me
## Known Issues ## Known Issues
- Everything - Everything
- See linear page.
## Run Locally ## Run Locally
If not installed, install [uv](https://docs.astral.sh/uv/)
Clone the project Clone the project
```bash ```bash
@@ -54,7 +86,21 @@ Start the game
uv run PyTaiko.py uv run PyTaiko.py
``` ```
## Compilation
Windows/Mac OS:
```
uv add nuitka
uv run nuitka --mode=app --noinclude-setuptools-mode=nofollow --noinclude-IPython-mode=nofollow --assume-yes-for-downloads PyTaiko.py
```
Linux:
Install portaudio with `sudo apt install portaudio19-dev`
Arch Linux only:
Install [patchelf](https://github.com/NixOS/patchelf)
Run this command
```
sudo ln -s /lib/libatomic.so /lib/libatomic.a
```
## FAQ ## FAQ

View File

@@ -4,6 +4,7 @@ from pathlib import Path
import pyray as ray import pyray as ray
from libs.animation import Animation from libs.animation import Animation
from libs.texture import TextureWrapper
from libs.utils import load_all_textures_from_zip from libs.utils import load_all_textures_from_zip
@@ -11,10 +12,12 @@ class Background:
def __init__(self, screen_width: int, screen_height: int): def __init__(self, screen_width: int, screen_height: int):
self.screen_width = screen_width self.screen_width = screen_width
self.screen_height = screen_height self.screen_height = screen_height
self.donbg = DonBG.create(self.screen_width, self.screen_height, random.randint(1, 6), 1) self.tex_wrapper = TextureWrapper()
self.tex_wrapper.load_animations('background')
self.donbg = DonBG.create(self.tex_wrapper, self.screen_width, self.screen_height, random.randint(1, 6), 1)
self.bg_normal = BGNormal.create(self.screen_width, self.screen_height, random.randint(1, 5)) self.bg_normal = BGNormal.create(self.screen_width, self.screen_height, random.randint(1, 5))
self.bg_fever = BGFever.create(self.screen_width, self.screen_height, 4) self.bg_fever = BGFever.create(self.screen_width, self.screen_height, 4)
self.footer = Footer(self.screen_width, self.screen_height, random.randint(1, 3)) self.footer = Footer(self.tex_wrapper, random.randint(0, 2))
self.is_clear = False self.is_clear = False
def update(self, current_time_ms: float, is_clear: bool): def update(self, current_time_ms: float, is_clear: bool):
if not self.is_clear and is_clear: if not self.is_clear and is_clear:
@@ -27,27 +30,27 @@ class Background:
self.bg_normal.draw() self.bg_normal.draw()
if self.is_clear: if self.is_clear:
self.bg_fever.draw() self.bg_fever.draw()
self.footer.draw() self.footer.draw(self.tex_wrapper)
self.donbg.draw() self.donbg.draw()
def unload(self): def unload(self):
self.donbg.unload() self.donbg.unload()
self.bg_normal.unload() self.bg_normal.unload()
self.bg_fever.unload() self.bg_fever.unload()
self.footer.unload()
class DonBG: class DonBG:
@staticmethod @staticmethod
def create(screen_width: int, screen_height: int, index: int, player_num: int): def create(tex: TextureWrapper, screen_width: int, screen_height: int, index: int, player_num: int):
map = [None, DonBG1, DonBG2, DonBG3, DonBG4, DonBG5, DonBG6] map = [None, DonBG1, DonBG2, DonBG3, DonBG4, DonBG5, DonBG6]
selected_obj = map[index] selected_obj = map[index]
return selected_obj(index, screen_width, screen_height, player_num) return selected_obj(tex, index, screen_width, screen_height, player_num)
class DonBGBase: class DonBGBase:
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int): def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
self.screen_width = screen_width self.screen_width = screen_width
self.screen_height = screen_height self.screen_height = screen_height
#tex.load_zip('background', f'donbg/{index}_{player_num}')
self.player_num = player_num self.player_num = player_num
self.name = 'donbg_a_' + str(index).zfill(2) self.name = 'donbg_a_' + str(index).zfill(2)
self.textures = (load_all_textures_from_zip(Path(f'Graphics/lumendata/enso_original/{self.name}_{self.player_num}p.zip'))) self.textures = (load_all_textures_from_zip(Path(f'Graphics/lumendata/enso_original/{self.name}_{self.player_num}p.zip')))
@@ -73,8 +76,8 @@ class DonBGBase:
ray.unload_texture(texture) ray.unload_texture(texture)
class DonBG1(DonBGBase): class DonBG1(DonBGBase):
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int): def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
super().__init__(index, screen_width, screen_height, player_num) super().__init__(tex, index, screen_width, screen_height, player_num)
self.overlay_move = Animation.create_move(1000, start_position=0, total_distance=20, reverse_delay=0) self.overlay_move = Animation.create_move(1000, start_position=0, total_distance=20, reverse_delay=0)
self.overlay_move.start() self.overlay_move.start()
def update(self, current_time_ms: float, is_clear: bool): def update(self, current_time_ms: float, is_clear: bool):
@@ -100,8 +103,8 @@ class DonBG1(DonBGBase):
ray.draw_texture(texture, i + int(self.move.attribute * (texture.width/top_texture.width)*3), int(self.overlay_move.attribute) + 105, color) ray.draw_texture(texture, i + int(self.move.attribute * (texture.width/top_texture.width)*3), int(self.overlay_move.attribute) + 105, color)
class DonBG2(DonBGBase): class DonBG2(DonBGBase):
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int): def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
super().__init__(index, screen_width, screen_height, player_num) super().__init__(tex, index, screen_width, screen_height, player_num)
self.overlay_move = Animation.create_move(1500, start_position=0, total_distance=20, reverse_delay=0) self.overlay_move = Animation.create_move(1500, start_position=0, total_distance=20, reverse_delay=0)
self.overlay_move.start() self.overlay_move.start()
def update(self, current_time_ms: float, is_clear: bool): def update(self, current_time_ms: float, is_clear: bool):
@@ -123,8 +126,8 @@ class DonBG2(DonBGBase):
ray.draw_texture(texture, i + int(self.move.attribute), int(self.overlay_move.attribute) - 25, color) ray.draw_texture(texture, i + int(self.move.attribute), int(self.overlay_move.attribute) - 25, color)
class DonBG3(DonBGBase): class DonBG3(DonBGBase):
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int): def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
super().__init__(index, screen_width, screen_height, player_num) super().__init__(tex, index, screen_width, screen_height, player_num)
duration = 266 duration = 266
bounce_distance = 40 bounce_distance = 40
self.bounce_up = Animation.create_move(duration, total_distance=-bounce_distance, ease_out='quadratic') self.bounce_up = Animation.create_move(duration, total_distance=-bounce_distance, ease_out='quadratic')
@@ -162,8 +165,8 @@ class DonBG3(DonBGBase):
ray.draw_texture(texture, i + int(self.move.attribute*2), int(self.bounce_up.attribute) - int(self.bounce_down.attribute) - 25 + int(self.overlay_move.attribute) + int(self.overlay_move_2.attribute), color) ray.draw_texture(texture, i + int(self.move.attribute*2), int(self.bounce_up.attribute) - int(self.bounce_down.attribute) - 25 + int(self.overlay_move.attribute) + int(self.overlay_move_2.attribute), color)
class DonBG4(DonBGBase): class DonBG4(DonBGBase):
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int): def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
super().__init__(index, screen_width, screen_height, player_num) super().__init__(tex, index, screen_width, screen_height, player_num)
self.overlay_move = Animation.create_move(1500, start_position=0, total_distance=20, reverse_delay=0) self.overlay_move = Animation.create_move(1500, start_position=0, total_distance=20, reverse_delay=0)
self.overlay_move.start() self.overlay_move.start()
def update(self, current_time_ms: float, is_clear: bool): def update(self, current_time_ms: float, is_clear: bool):
@@ -186,8 +189,8 @@ class DonBG4(DonBGBase):
ray.draw_texture(texture, i + int(self.move.attribute), int(self.overlay_move.attribute) - 25, color) ray.draw_texture(texture, i + int(self.move.attribute), int(self.overlay_move.attribute) - 25, color)
class DonBG5(DonBGBase): class DonBG5(DonBGBase):
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int): def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
super().__init__(index, screen_width, screen_height, player_num) super().__init__(tex, index, screen_width, screen_height, player_num)
duration = 266 duration = 266
bounce_distance = 40 bounce_distance = 40
self.bounce_up = Animation.create_move(duration, total_distance=-bounce_distance, ease_out='quadratic') self.bounce_up = Animation.create_move(duration, total_distance=-bounce_distance, ease_out='quadratic')
@@ -221,8 +224,8 @@ class DonBG5(DonBGBase):
ray.draw_texture(texture, i + int((self.move.attribute * (texture.width/top_texture.width))*2), int(self.bounce_up.attribute) - int(self.bounce_down.attribute) - int(self.adjust.attribute), color) ray.draw_texture(texture, i + int((self.move.attribute * (texture.width/top_texture.width))*2), int(self.bounce_up.attribute) - int(self.bounce_down.attribute) - int(self.adjust.attribute), color)
class DonBG6(DonBGBase): class DonBG6(DonBGBase):
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int): def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
super().__init__(index, screen_width, screen_height, player_num) super().__init__(tex, index, screen_width, screen_height, player_num)
self.overlay_move = Animation.create_move(1000, start_position=0, total_distance=20, reverse_delay=0) self.overlay_move = Animation.create_move(1000, start_position=0, total_distance=20, reverse_delay=0)
self.overlay_move.start() self.overlay_move.start()
def update(self, current_time_ms: float, is_clear: bool): def update(self, current_time_ms: float, is_clear: bool):
@@ -498,14 +501,8 @@ class BGFever4(BGFeverBase):
ray.draw_texture(self.textures[self.name][2], self.textures[self.name][2].width -int(self.horizontal_move.attribute), y, ray.WHITE) ray.draw_texture(self.textures[self.name][2], self.textures[self.name][2].width -int(self.horizontal_move.attribute), y, ray.WHITE)
class Footer: class Footer:
def __init__(self, screen_width: int, screen_height: int, index: int): def __init__(self, tex: TextureWrapper, index: int):
self.screen_width = screen_width self.index = index
self.screen_height = screen_height tex.load_zip('background', 'footer')
self.name = 'dodai_a_' + str(index).zfill(2) def draw(self, tex: TextureWrapper):
self.textures = (load_all_textures_from_zip(Path(f'Graphics/lumendata/enso_original/{self.name}.zip'))) tex.draw_texture('footer', str(self.index))
def unload(self):
for texture_group in self.textures:
for texture in self.textures[texture_group]:
ray.unload_texture(texture)
def draw(self):
ray.draw_texture(self.textures[self.name][0], 0, self.screen_height - self.textures[self.name][0].height + 20, ray.WHITE)

View File

@@ -63,6 +63,55 @@ class TextureWrapper:
tex_object.x2 = tex_mapping.get("x2", tex_object.width) tex_object.x2 = tex_mapping.get("x2", tex_object.width)
tex_object.y2 = tex_mapping.get("y2", tex_object.height) tex_object.y2 = tex_mapping.get("y2", tex_object.height)
def load_animations(self, screen_name: str):
screen_path = self.graphics_path / screen_name
if (screen_path / 'animation.json').exists():
with open(screen_path / 'animation.json') as json_file:
self.animations = parse_animations(json.loads(json_file.read()))
def load_zip(self, screen_name: str, subset: str):
zip = (self.graphics_path / screen_name / subset).with_suffix('.zip')
with zipfile.ZipFile(zip, 'r') as zip_ref:
if 'texture.json' not in zip_ref.namelist():
raise Exception(f"texture.json file missing from {zip}")
with zip_ref.open('texture.json') as json_file:
tex_mapping_data = json.loads(json_file.read().decode('utf-8'))
self.textures[zip.stem] = dict()
for tex_name in tex_mapping_data:
if f"{tex_name}/" in zip_ref.namelist():
tex_mapping = tex_mapping_data[tex_name]
with tempfile.TemporaryDirectory() as temp_dir:
zip_ref.extractall(temp_dir, members=[name for name in zip_ref.namelist()
if name.startswith(tex_name)])
extracted_path = Path(temp_dir) / tex_name
if extracted_path.is_dir():
frames = [ray.load_texture(str(frame)) for frame in sorted(extracted_path.iterdir(),
key=lambda x: int(x.stem)) if frame.is_file()]
else:
frames = [ray.load_texture(str(extracted_path))]
self.textures[zip.stem][tex_name] = Texture(tex_name, frames, tex_mapping)
self._read_tex_obj_data(tex_mapping, self.textures[zip.stem][tex_name])
elif f"{tex_name}.png" in zip_ref.namelist():
tex_mapping = tex_mapping_data[tex_name]
png_filename = f"{tex_name}.png"
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as temp_file:
temp_file.write(zip_ref.read(png_filename))
temp_path = temp_file.name
try:
tex = ray.load_texture(temp_path)
self.textures[zip.stem][tex_name] = Texture(tex_name, tex, tex_mapping)
self._read_tex_obj_data(tex_mapping, self.textures[zip.stem][tex_name])
finally:
os.unlink(temp_path)
else:
raise Exception(f"Texture {tex_name} was not found in {zip}")
def load_screen_textures(self, screen_name: str) -> None: def load_screen_textures(self, screen_name: str) -> None:
self.unload_textures() self.unload_textures()
screen_path = self.graphics_path / screen_name screen_path = self.graphics_path / screen_name
@@ -72,51 +121,18 @@ class TextureWrapper:
for zip in screen_path.iterdir(): for zip in screen_path.iterdir():
if zip.is_dir() or zip.suffix != ".zip": if zip.is_dir() or zip.suffix != ".zip":
continue continue
with zipfile.ZipFile(zip, 'r') as zip_ref: self.load_zip(screen_name, zip.name)
if 'texture.json' not in zip_ref.namelist():
raise Exception(f"texture.json file missing from {zip}")
with zip_ref.open('texture.json') as json_file:
tex_mapping_data = json.loads(json_file.read().decode('utf-8'))
self.textures[zip.stem] = dict()
for tex_name in tex_mapping_data:
if f"{tex_name}/" in zip_ref.namelist():
tex_mapping = tex_mapping_data[tex_name]
with tempfile.TemporaryDirectory() as temp_dir:
zip_ref.extractall(temp_dir, members=[name for name in zip_ref.namelist()
if name.startswith(tex_name)])
extracted_path = Path(temp_dir) / tex_name
if extracted_path.is_dir():
frames = [ray.load_texture(str(frame)) for frame in sorted(extracted_path.iterdir(),
key=lambda x: int(x.stem)) if frame.is_file()]
else:
frames = [ray.load_texture(str(extracted_path))]
self.textures[zip.stem][tex_name] = Texture(tex_name, frames, tex_mapping)
self._read_tex_obj_data(tex_mapping, self.textures[zip.stem][tex_name])
elif f"{tex_name}.png" in zip_ref.namelist():
tex_mapping = tex_mapping_data[tex_name]
png_filename = f"{tex_name}.png"
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as temp_file:
temp_file.write(zip_ref.read(png_filename))
temp_path = temp_file.name
try:
tex = ray.load_texture(temp_path)
self.textures[zip.stem][tex_name] = Texture(tex_name, tex, tex_mapping)
self._read_tex_obj_data(tex_mapping, self.textures[zip.stem][tex_name])
finally:
os.unlink(temp_path)
else:
raise Exception(f"Texture {tex_name} was not found in {zip}")
def draw_texture(self, subset: str, texture: str, color: ray.Color=ray.WHITE, frame: int = 0, scale: float = 1.0, center: bool = False, mirror: str = '', x: float = 0, y: float = 0, x2: float = 0, y2: float = 0, origin: ray.Vector2 = ray.Vector2(0,0), rotation: float = 0) -> None: def draw_texture(self, subset: str, texture: str, color: ray.Color=ray.WHITE, frame: int = 0, scale: float = 1.0, center: bool = False,
mirror: str = '', x: float = 0, y: float = 0, x2: float = 0, y2: float = 0,
origin: ray.Vector2 = ray.Vector2(0,0), rotation: float = 0, fade: float = 1.1) -> None:
mirror_x = -1 if mirror == 'horizontal' else 1 mirror_x = -1 if mirror == 'horizontal' else 1
mirror_y = -1 if mirror == 'vertical' else 1 mirror_y = -1 if mirror == 'vertical' else 1
if fade != 1.1:
final_color = ray.fade(color, fade)
else:
final_color = color
tex_object = self.textures[subset][texture] tex_object = self.textures[subset][texture]
source_rect = ray.Rectangle(0, 0, tex_object.width * mirror_x, tex_object.height * mirror_y) source_rect = ray.Rectangle(0, 0, tex_object.width * mirror_x, tex_object.height * mirror_y)
if center: if center:
@@ -128,10 +144,10 @@ class TextureWrapper:
raise Exception("Texture was marked as multiframe but is only 1 texture") raise Exception("Texture was marked as multiframe but is only 1 texture")
if frame >= len(tex_object.texture): if frame >= len(tex_object.texture):
raise Exception(f"Frame {frame} not available in iterable texture {tex_object.name}") raise Exception(f"Frame {frame} not available in iterable texture {tex_object.name}")
ray.draw_texture_pro(tex_object.texture[frame], source_rect, dest_rect, origin, rotation, color) ray.draw_texture_pro(tex_object.texture[frame], source_rect, dest_rect, origin, rotation, final_color)
else: else:
if isinstance(tex_object.texture, list): if isinstance(tex_object.texture, list):
raise Exception("Texture is multiframe but was called as 1 texture") raise Exception("Texture is multiframe but was called as 1 texture")
ray.draw_texture_pro(tex_object.texture, source_rect, dest_rect, origin, rotation, color) ray.draw_texture_pro(tex_object.texture, source_rect, dest_rect, origin, rotation, final_color)
tex = TextureWrapper() tex = TextureWrapper()

View File

@@ -1,11 +1,10 @@
import pyray as ray import pyray as ray
from libs.animation import Animation
from libs.utils import OutlinedText, global_data from libs.utils import OutlinedText, global_data
class Transition: class Transition:
def __init__(self, title: str, subtitle: str) -> None: def __init__(self, title: str, subtitle: str, is_second: bool = False) -> None:
self.is_finished = False self.is_finished = False
self.rainbow_up = global_data.tex.get_animation(0) self.rainbow_up = global_data.tex.get_animation(0)
self.mini_up = global_data.tex.get_animation(1) self.mini_up = global_data.tex.get_animation(1)
@@ -14,7 +13,7 @@ class Transition:
self.song_info_fade_out = global_data.tex.get_animation(4) self.song_info_fade_out = global_data.tex.get_animation(4)
self.title = OutlinedText(title, 40, ray.WHITE, ray.BLACK, outline_thickness=5) 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.subtitle = OutlinedText(subtitle, 30, ray.WHITE, ray.BLACK, outline_thickness=5)
self.is_second = False self.is_second = is_second
def start(self): def start(self):
self.rainbow_up.start() self.rainbow_up.start()
@@ -67,59 +66,3 @@ class Transition:
global_data.tex.draw_texture('rainbow_transition', 'chara_center', y=-self.rainbow_up.attribute + offset - total_offset) global_data.tex.draw_texture('rainbow_transition', 'chara_center', y=-self.rainbow_up.attribute + offset - total_offset)
self.draw_song_info() self.draw_song_info()
class Transition2:
def __init__(self, screen_height: int, title: str, subtitle: str) -> None:
duration = 266
self.is_finished = False
self.rainbow_up = Animation.create_move(duration, start_position=0, total_distance=screen_height + global_data.textures['scene_change_rainbow'][2].height, ease_in='cubic')
self.rainbow_up.start()
self.chara_down = None
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.song_info_fade = Animation.create_fade(duration/2)
self.song_info_fade.start()
def update(self, current_time_ms: float):
self.rainbow_up.update(current_time_ms)
self.song_info_fade.update(current_time_ms)
if self.rainbow_up.is_finished and self.chara_down is None:
self.chara_down = Animation.create_move(33, start_position=0, total_distance=30)
self.chara_down.start()
if self.chara_down is not None:
self.chara_down.update(current_time_ms)
self.is_finished = self.chara_down.is_finished
def draw_song_info(self):
texture = global_data.textures['scene_change_rainbow'][6]
y = 720//2 - texture.height
src = ray.Rectangle(0, 0, texture.width, texture.height)
dest = ray.Rectangle(1280//2 - (texture.width*3)//2, y, texture.width*3, texture.height*2)
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, min(0.70, self.song_info_fade.attribute)))
texture = self.title.texture
y = 720//2 - texture.height//2 - 20
src = ray.Rectangle(0, 0, texture.width, texture.height)
dest = ray.Rectangle(1280//2 - texture.width//2, y, texture.width, texture.height)
self.title.draw(src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, self.song_info_fade.attribute))
texture = self.subtitle.texture
src = ray.Rectangle(0, 0, texture.width, texture.height)
dest = ray.Rectangle(1280//2 - texture.width//2, y + 50, texture.width, texture.height)
self.subtitle.draw(src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, self.song_info_fade.attribute))
def draw(self, screen_height: int):
ray.draw_texture(global_data.textures['scene_change_rainbow'][1], 0, screen_height - int(self.rainbow_up.attribute), ray.WHITE)
texture = global_data.textures['scene_change_rainbow'][0]
src = ray.Rectangle(0, 0, texture.width, texture.height)
dest = ray.Rectangle(0, -int(self.rainbow_up.attribute), texture.width, screen_height)
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
texture = global_data.textures['scene_change_rainbow'][3]
offset = 0
if self.chara_down is not None:
offset = int(self.chara_down.attribute)
ray.draw_texture(global_data.textures['scene_change_rainbow'][4], 142, 14 -int(self.rainbow_up.attribute*3) - offset, ray.WHITE)
ray.draw_texture(global_data.textures['scene_change_rainbow'][5], 958, 144 -int(self.rainbow_up.attribute*3) - offset, ray.WHITE)
ray.draw_texture(texture, 76, -int(self.rainbow_up.attribute*3) - offset, ray.WHITE)
self.draw_song_info()

View File

@@ -197,11 +197,6 @@ def is_r_kat_pressed() -> bool:
return False return False
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 @dataclass
class SessionData: class SessionData:
selected_difficulty: int = 0 selected_difficulty: int = 0

View File

@@ -15,14 +15,6 @@ dependencies = [
"gitpython>=3.1.44", "gitpython>=3.1.44",
] ]
[dependency-groups] [tool.vulture]
dev = [] exclude = ["*.git", "*./.github", "*./.venv", "*./cache"]
paths = ["."]
[tool.codeflash]
# All paths are relative to this pyproject.toml's directory.
module-root = "."
tests-root = "tests"
test-framework = "pytest"
ignore-paths = []
disable-telemetry = true
formatter-cmds = ["disabled"]

View File

@@ -122,7 +122,7 @@ class EntryScreen:
tex.draw_texture('background', 'people') tex.draw_texture('background', 'people')
tex.draw_texture('background', 'shops_left') tex.draw_texture('background', 'shops_left')
tex.draw_texture('background', 'shops_right') tex.draw_texture('background', 'shops_right')
tex.draw_texture('background', 'lights', scale=2.0, color=ray.fade(ray.WHITE, self.bg_flicker.attribute)) tex.draw_texture('background', 'lights', scale=2.0, fade=self.bg_flicker.attribute)
def draw_footer(self): def draw_footer(self):
tex.draw_texture('side_select', 'footer') tex.draw_texture('side_select', 'footer')
@@ -132,35 +132,34 @@ class EntryScreen:
tex.draw_texture('side_select', 'footer_right') tex.draw_texture('side_select', 'footer_right')
def draw_side_select(self, fade): def draw_side_select(self, fade):
color = ray.fade(ray.WHITE, fade) tex.draw_texture('side_select', 'box_top_left', fade=fade)
tex.draw_texture('side_select', 'box_top_left', color=color) tex.draw_texture('side_select', 'box_top_right', fade=fade)
tex.draw_texture('side_select', 'box_top_right', color=color) tex.draw_texture('side_select', 'box_bottom_left', fade=fade)
tex.draw_texture('side_select', 'box_bottom_left', color=color) tex.draw_texture('side_select', 'box_bottom_right', fade=fade)
tex.draw_texture('side_select', 'box_bottom_right', color=color)
tex.draw_texture('side_select', 'box_top', color=color) tex.draw_texture('side_select', 'box_top', fade=fade)
tex.draw_texture('side_select', 'box_bottom', color=color) tex.draw_texture('side_select', 'box_bottom', fade=fade)
tex.draw_texture('side_select', 'box_left', color=color) tex.draw_texture('side_select', 'box_left', fade=fade)
tex.draw_texture('side_select', 'box_right', color=color) tex.draw_texture('side_select', 'box_right', fade=fade)
tex.draw_texture('side_select', 'box_center', color=color) tex.draw_texture('side_select', 'box_center', fade=fade)
tex.draw_texture('side_select', 'question', color=color) tex.draw_texture('side_select', 'question', fade=fade)
tex.draw_texture('side_select', '1P', color=color) tex.draw_texture('side_select', '1P', fade=fade)
tex.draw_texture('side_select', 'cancel', color=color) tex.draw_texture('side_select', 'cancel', fade=fade)
tex.draw_texture('side_select', '2P', color=color) tex.draw_texture('side_select', '2P', fade=fade)
if self.side == 0: if self.side == 0:
tex.draw_texture('side_select', '1P_highlight', color=color) tex.draw_texture('side_select', '1P_highlight', fade=fade)
tex.textures['side_select']['1P2P_outline'].x = 261 tex.textures['side_select']['1P2P_outline'].x = 261
tex.draw_texture('side_select', '1P2P_outline', color=color, mirror='horizontal') tex.draw_texture('side_select', '1P2P_outline', fade=fade, mirror='horizontal')
elif self.side == 1: elif self.side == 1:
tex.draw_texture('side_select', 'cancel_highlight', color=color) tex.draw_texture('side_select', 'cancel_highlight', fade=fade)
tex.draw_texture('side_select', 'cancel_outline', color=color) tex.draw_texture('side_select', 'cancel_outline', fade=fade)
else: else:
tex.draw_texture('side_select', '2P_highlight', color=color) tex.draw_texture('side_select', '2P_highlight', fade=fade)
tex.textures['side_select']['1P2P_outline'].x = 762 tex.textures['side_select']['1P2P_outline'].x = 762
tex.draw_texture('side_select', '1P2P_outline', color=color) tex.draw_texture('side_select', '1P2P_outline', fade=fade)
tex.draw_texture('side_select', 'cancel_text', color=color) tex.draw_texture('side_select', 'cancel_text', fade=fade)
def draw_player_drum(self): def draw_player_drum(self):
move_x = self.drum_move_3.attribute move_x = self.drum_move_3.attribute
@@ -179,10 +178,9 @@ class EntryScreen:
scale = self.cloud_resize.attribute scale = self.cloud_resize.attribute
if self.cloud_resize.is_finished: if self.cloud_resize.is_finished:
scale = max(1, self.cloud_resize_loop.attribute) scale = max(1, self.cloud_resize_loop.attribute)
color = ray.fade(ray.WHITE, self.cloud_fade.attribute)
tex.update_attr('side_select', 'cloud', 'x', move_x) tex.update_attr('side_select', 'cloud', 'x', move_x)
tex.update_attr('side_select', 'cloud', 'y', move_y) tex.update_attr('side_select', 'cloud', 'y', move_y)
tex.draw_texture('side_select', 'cloud', frame=self.cloud_texture_change.attribute, color=color, scale=scale, center=True) tex.draw_texture('side_select', 'cloud', frame=self.cloud_texture_change.attribute, fade=self.cloud_fade.attribute, scale=scale, center=True)
def draw_mode_select(self): def draw_mode_select(self):
self.draw_player_drum() self.draw_player_drum()

View File

@@ -45,7 +45,6 @@ class GameScreen:
self.sound_restart = audio.load_sound(sounds_dir / 'song_select' / 'Skip.ogg') self.sound_restart = audio.load_sound(sounds_dir / 'song_select' / 'Skip.ogg')
self.sound_balloon_pop = audio.load_sound(sounds_dir / "balloon_pop.wav") self.sound_balloon_pop = audio.load_sound(sounds_dir / "balloon_pop.wav")
self.sound_result_transition = audio.load_sound(sounds_dir / "result" / "VO_RESULT [1].ogg") self.sound_result_transition = audio.load_sound(sounds_dir / "result" / "VO_RESULT [1].ogg")
self.sounds = [self.sound_don, self.sound_kat, self.sound_balloon_pop, self.sound_result_transition]
def init_tja(self, song: Path, difficulty: int): def init_tja(self, song: Path, difficulty: int):
if song == Path(''): if song == Path(''):
@@ -82,8 +81,7 @@ class GameScreen:
subtitle = self.tja.metadata.subtitle.get(global_data.config['general']['language'].lower(), '') subtitle = self.tja.metadata.subtitle.get(global_data.config['general']['language'].lower(), '')
else: else:
subtitle = '' subtitle = ''
self.transition = Transition(session_data.song_title, subtitle) self.transition = Transition(session_data.song_title, subtitle, is_second=True)
self.transition.is_second = True
self.transition.start() self.transition.start()
def on_screen_end(self, next_screen): def on_screen_end(self, next_screen):
@@ -242,13 +240,6 @@ class Player:
self.autoplay_hit_side = 'L' self.autoplay_hit_side = 'L'
self.last_subdivision = -1 self.last_subdivision = -1
self.model = ray.load_model("model/mikudon.obj")
self.model_position = ray.Vector3(-475.0, 160.0, -180.0)
self.model_scale = 850.0
self.model_rotation_y = 30.0 # Face towards camera (rotate 180 degrees on Y-axis)
self.model_rotation_x = 0.0 # No up/down tilt
self.model_rotation_z = 0.0
def get_result_score(self): def get_result_score(self):
return self.score, self.good_count, self.ok_count, self.bad_count, self.total_drumroll, self.max_combo return self.score, self.good_count, self.ok_count, self.bad_count, self.total_drumroll, self.max_combo
@@ -657,17 +648,6 @@ class Player:
#ray.draw_circle(game_screen.width//2, game_screen.height, 300, ray.ORANGE) #ray.draw_circle(game_screen.width//2, game_screen.height, 300, ray.ORANGE)
def draw_3d(self): def draw_3d(self):
'''
rotation_axis = ray.Vector3(0.0, 1.0, 0.0) # Y-axis for horizontal rotation
ray.draw_model_ex(
self.model,
self.model_position,
rotation_axis,
self.model_rotation_y,
ray.Vector3(self.model_scale, self.model_scale, self.model_scale),
ray.WHITE
)
'''
pass pass
class Judgement: class Judgement:
@@ -729,53 +709,47 @@ class Judgement:
class LaneHitEffect: class LaneHitEffect:
def __init__(self, type: str): def __init__(self, type: str):
self.type = type self.type = type
self.color = ray.fade(ray.WHITE, 0.5)
self.fade = tex.get_animation(0, is_copy=True) self.fade = tex.get_animation(0, is_copy=True)
self.fade.start() self.fade.start()
self.is_finished = False self.is_finished = False
def update(self, current_ms: float): def update(self, current_ms: float):
self.fade.update(current_ms) self.fade.update(current_ms)
fade_opacity = self.fade.attribute
self.color = ray.fade(ray.WHITE, fade_opacity)
if self.fade.is_finished: if self.fade.is_finished:
self.is_finished = True self.is_finished = True
def draw(self): def draw(self):
if self.type == 'GOOD': if self.type == 'GOOD':
tex.draw_texture('lane', 'lane_hit_effect', frame=2, color=self.color) tex.draw_texture('lane', 'lane_hit_effect', frame=2, fade=self.fade.attribute)
elif self.type == 'DON': elif self.type == 'DON':
tex.draw_texture('lane', 'lane_hit_effect', frame=0, color=self.color) tex.draw_texture('lane', 'lane_hit_effect', frame=0, fade=self.fade.attribute)
elif self.type == 'KAT': elif self.type == 'KAT':
tex.draw_texture('lane', 'lane_hit_effect', frame=1, color=self.color) tex.draw_texture('lane', 'lane_hit_effect', frame=1, fade=self.fade.attribute)
class DrumHitEffect: class DrumHitEffect:
def __init__(self, type: str, side: str): def __init__(self, type: str, side: str):
self.type = type self.type = type
self.side = side self.side = side
self.color = ray.fade(ray.WHITE, 1)
self.is_finished = False self.is_finished = False
self.fade = tex.get_animation(1, is_copy=True) self.fade = tex.get_animation(1, is_copy=True)
self.fade.start() self.fade.start()
def update(self, current_ms: float): def update(self, current_ms: float):
self.fade.update(current_ms) self.fade.update(current_ms)
fade_opacity = self.fade.attribute
self.color = ray.fade(ray.WHITE, fade_opacity)
if self.fade.is_finished: if self.fade.is_finished:
self.is_finished = True self.is_finished = True
def draw(self): def draw(self):
if self.type == 'DON': if self.type == 'DON':
if self.side == 'L': if self.side == 'L':
tex.draw_texture('lane', 'drum_don_l', color=self.color) tex.draw_texture('lane', 'drum_don_l', fade=self.fade.attribute)
elif self.side == 'R': elif self.side == 'R':
tex.draw_texture('lane', 'drum_don_r', color=self.color) tex.draw_texture('lane', 'drum_don_r', fade=self.fade.attribute)
elif self.type == 'KAT': elif self.type == 'KAT':
if self.side == 'L': if self.side == 'L':
tex.draw_texture('lane', 'drum_kat_l', color=self.color) tex.draw_texture('lane', 'drum_kat_l', fade=self.fade.attribute)
elif self.side == 'R': elif self.side == 'R':
tex.draw_texture('lane', 'drum_kat_r', color=self.color) tex.draw_texture('lane', 'drum_kat_r', fade=self.fade.attribute)
class GaugeHitEffect: class GaugeHitEffect:
def __init__(self, note_type: int, big: bool): def __init__(self, note_type: int, big: bool):
@@ -820,7 +794,7 @@ class GaugeHitEffect:
origin = ray.Vector2(dest_width / 2, dest_height / 2) origin = ray.Vector2(dest_width / 2, dest_height / 2)
rotation = self.rotation.attribute*100 rotation = self.rotation.attribute*100
tex.draw_texture('gauge', 'hit_effect', frame=self.texture_change.attribute, x2=-152 + (152 * self.resize.attribute), y2=-152 + (152 * self.resize.attribute), color=ray.fade(texture_color, self.fade_out.attribute), origin=origin, rotation=rotation, center=True) tex.draw_texture('gauge', 'hit_effect', frame=self.texture_change.attribute, x2=-152 + (152 * self.resize.attribute), y2=-152 + (152 * self.resize.attribute), color=ray.fade(texture_color, self.fade_out.attribute), origin=origin, rotation=rotation, center=True)
tex.draw_texture('notes', str(self.note_type), x=1158, y=101, color=ray.fade(ray.WHITE, self.fade_out.attribute)) tex.draw_texture('notes', str(self.note_type), x=1158, y=101, fade=self.fade_out.attribute)
if self.is_big: if self.is_big:
tex.draw_texture('gauge', 'hit_effect_circle_big', color=self.color) tex.draw_texture('gauge', 'hit_effect_circle_big', color=self.color)
else: else:
@@ -1154,7 +1128,7 @@ class SongInfo:
self.fade.restart() self.fade.restart()
def draw(self): def draw(self):
tex.draw_texture('song_info', 'song_num', color=ray.fade(ray.WHITE, self.fade.attribute), frame=global_data.songs_played % 4) tex.draw_texture('song_info', 'song_num', fade=self.fade.attribute, frame=global_data.songs_played % 4)
text_x = 1252 - self.song_title.texture.width text_x = 1252 - self.song_title.texture.width
text_y = 50 - self.song_title.texture.height//2 text_y = 50 - self.song_title.texture.height//2
@@ -1187,7 +1161,6 @@ class ResultTransition:
x += 256 x += 256
class Gauge: class Gauge:
GAUGE_MAX = 87
def __init__(self, difficulty: int, level: int, total_notes: int): def __init__(self, difficulty: int, level: int, total_notes: int):
self.gauge_length = 0 self.gauge_length = 0
self.previous_length = 0 self.previous_length = 0
@@ -1300,16 +1273,16 @@ class Gauge:
tex.draw_texture('gauge', 'bar', x=i*8) tex.draw_texture('gauge', 'bar', x=i*8)
if gauge_length == 87 and self.rainbow_fade_in is not None and self.rainbow_animation is not None: if gauge_length == 87 and self.rainbow_fade_in is not None and self.rainbow_animation is not None:
if 0 < self.rainbow_animation.attribute < 8: if 0 < self.rainbow_animation.attribute < 8:
tex.draw_texture('gauge', 'rainbow', frame=self.rainbow_animation.attribute-1, color=ray.fade(ray.WHITE, self.rainbow_fade_in.attribute)) tex.draw_texture('gauge', 'rainbow', frame=self.rainbow_animation.attribute-1, fade=self.rainbow_fade_in.attribute)
tex.draw_texture('gauge', 'rainbow', frame=self.rainbow_animation.attribute, color=ray.fade(ray.WHITE, self.rainbow_fade_in.attribute)) tex.draw_texture('gauge', 'rainbow', frame=self.rainbow_animation.attribute, fade=self.rainbow_fade_in.attribute)
if self.gauge_update_anim is not None and gauge_length < 88 and gauge_length > self.previous_length: if self.gauge_update_anim is not None and gauge_length < 88 and gauge_length > self.previous_length:
if gauge_length == 69: if gauge_length == 69:
tex.draw_texture('gauge', 'bar_clear_transition_fade', x=gauge_length*8, color=ray.fade(ray.WHITE, self.gauge_update_anim.attribute)) tex.draw_texture('gauge', 'bar_clear_transition_fade', x=gauge_length*8, fade=self.gauge_update_anim.attribute)
elif gauge_length > 69: elif gauge_length > 69:
tex.draw_texture('gauge', 'bar_clear_fade', x=gauge_length*8, color=ray.fade(ray.WHITE, self.gauge_update_anim.attribute)) tex.draw_texture('gauge', 'bar_clear_fade', x=gauge_length*8, fade=self.gauge_update_anim.attribute)
else: else:
tex.draw_texture('gauge', 'bar_fade', x=gauge_length*8, color=ray.fade(ray.WHITE, self.gauge_update_anim.attribute)) tex.draw_texture('gauge', 'bar_fade', x=gauge_length*8, fade=self.gauge_update_anim.attribute)
tex.draw_texture('gauge', 'overlay', color=ray.fade(ray.WHITE, 0.15)) tex.draw_texture('gauge', 'overlay', fade=0.15)
if gauge_length >= 69: if gauge_length >= 69:
tex.draw_texture('gauge', 'clear') tex.draw_texture('gauge', 'clear')
tex.draw_texture('gauge', 'tamashii') tex.draw_texture('gauge', 'tamashii')

View File

@@ -182,10 +182,10 @@ class ResultScreen:
def draw_bottom_textures(self): def draw_bottom_textures(self):
if self.state == State.FAIL: if self.state == State.FAIL:
tex.draw_texture('background', 'gradient_fail', color=ray.fade(ray.WHITE, min(0.4, self.fade_in_bottom.attribute))) tex.draw_texture('background', 'gradient_fail', fade=min(0.4, self.fade_in_bottom.attribute))
else: else:
ray.begin_shader_mode(self.alpha_shader) ray.begin_shader_mode(self.alpha_shader)
tex.draw_texture('background', 'gradient_clear', color=ray.fade(ray.WHITE, self.fade_in_bottom.attribute)) tex.draw_texture('background', 'gradient_clear', fade=self.fade_in_bottom.attribute)
ray.end_shader_mode() ray.end_shader_mode()
self.bottom_characters.draw() self.bottom_characters.draw()
@@ -259,7 +259,7 @@ class Crown:
if self.resize.is_finished: if self.resize.is_finished:
scale = self.resize_fix.attribute scale = self.resize_fix.attribute
tex.draw_texture('crown', crown_name, scale=scale, center=True) tex.draw_texture('crown', crown_name, scale=scale, center=True)
tex.draw_texture('crown', 'crown_fade', color=ray.fade(ray.WHITE, self.white_fadein.attribute)) tex.draw_texture('crown', 'crown_fade', fade=self.white_fadein.attribute)
if self.gleam.attribute >= 0: if self.gleam.attribute >= 0:
tex.draw_texture('crown', 'gleam', frame=self.gleam.attribute) tex.draw_texture('crown', 'gleam', frame=self.gleam.attribute)
@@ -352,12 +352,11 @@ class FadeIn:
def draw(self): def draw(self):
x = 0 x = 0
color = ray.fade(ray.WHITE, self.fadein.attribute)
while x < 1280: while x < 1280:
tex.draw_texture('background', 'background_1p', x=x, y=-360, color=color) tex.draw_texture('background', 'background_1p', x=x, y=-360, fade=self.fadein.attribute)
tex.draw_texture('background', 'background_1p', x=x, y=360, color=color) tex.draw_texture('background', 'background_1p', x=x, y=360, fade=self.fadein.attribute)
tex.draw_texture('background', 'footer_1p', x=x, y=-77, color=color) tex.draw_texture('background', 'footer_1p', x=x, y=-77, fade=self.fadein.attribute)
tex.draw_texture('background', 'footer_1p', x=x, y=653, color=color) tex.draw_texture('background', 'footer_1p', x=x, y=653, fade=self.fadein.attribute)
x += 256 x += 256
class ScoreAnimator: class ScoreAnimator:
@@ -403,35 +402,34 @@ class Gauge:
self.is_finished = self.gauge_fade_in.is_finished self.is_finished = self.gauge_fade_in.is_finished
def draw(self): def draw(self):
color = ray.fade(ray.WHITE, self.gauge_fade_in.attribute)
scale = 10/11 scale = 10/11
tex.draw_texture('gauge', 'unfilled', scale=scale, color=color) tex.draw_texture('gauge', 'unfilled', scale=scale, fade=self.gauge_fade_in.attribute)
gauge_length = int(self.gauge_length) gauge_length = int(self.gauge_length)
if gauge_length == 87: if gauge_length == 87:
if 0 < self.rainbow_animation.attribute < 8: if 0 < self.rainbow_animation.attribute < 8:
tex.draw_texture('gauge', 'rainbow', frame=self.rainbow_animation.attribute-1, scale=scale, color=color) tex.draw_texture('gauge', 'rainbow', frame=self.rainbow_animation.attribute-1, scale=scale, fade=self.gauge_fade_in.attribute)
tex.draw_texture('gauge', 'rainbow', frame=self.rainbow_animation.attribute, scale=scale, color=color) tex.draw_texture('gauge', 'rainbow', frame=self.rainbow_animation.attribute, scale=scale, fade=self.gauge_fade_in.attribute)
else: else:
for i in range(gauge_length+1): for i in range(gauge_length+1):
width = int(i * 7.2) width = int(i * 7.2)
if i == 69: if i == 69:
tex.draw_texture('gauge', 'bar_clear_transition', x=width, scale=scale, color=color) tex.draw_texture('gauge', 'bar_clear_transition', x=width, scale=scale, fade=self.gauge_fade_in.attribute)
elif i > 69: elif i > 69:
if i % 5 == 0: if i % 5 == 0:
tex.draw_texture('gauge', 'bar_clear_top', x=width, scale=scale, color=color) tex.draw_texture('gauge', 'bar_clear_top', x=width, scale=scale, fade=self.gauge_fade_in.attribute)
tex.draw_texture('gauge', 'bar_clear_bottom', x=width, scale=scale, color=color) tex.draw_texture('gauge', 'bar_clear_bottom', x=width, scale=scale, fade=self.gauge_fade_in.attribute)
tex.draw_texture('gauge', 'bar_clear_top', x=width+1, scale=scale, color=color) tex.draw_texture('gauge', 'bar_clear_top', x=width+1, scale=scale, fade=self.gauge_fade_in.attribute)
tex.draw_texture('gauge', 'bar_clear_bottom', x=width+1, scale=scale, color=color) tex.draw_texture('gauge', 'bar_clear_bottom', x=width+1, scale=scale, fade=self.gauge_fade_in.attribute)
else: else:
if i % 5 == 0: if i % 5 == 0:
tex.draw_texture('gauge', 'bar', x=width, scale=scale, color=color) tex.draw_texture('gauge', 'bar', x=width, scale=scale, fade=self.gauge_fade_in.attribute)
tex.draw_texture('gauge', 'bar', x=width+1, scale=scale, color=color) tex.draw_texture('gauge', 'bar', x=width+1, scale=scale, fade=self.gauge_fade_in.attribute)
tex.draw_texture('gauge', 'overlay', scale=scale, color=ray.fade(ray.WHITE, min(0.15, self.gauge_fade_in.attribute))) tex.draw_texture('gauge', 'overlay', scale=scale, fade=min(0.15, self.gauge_fade_in.attribute))
tex.draw_texture('gauge', 'footer', scale=scale, color=color) tex.draw_texture('gauge', 'footer', scale=scale, fade=self.gauge_fade_in.attribute)
if gauge_length >= 69: if gauge_length >= 69:
tex.draw_texture('gauge', 'clear', scale=scale, color=color) tex.draw_texture('gauge', 'clear', scale=scale, fade=self.gauge_fade_in.attribute)
tex.draw_texture('gauge', 'tamashii', scale=scale, color=color) tex.draw_texture('gauge', 'tamashii', scale=scale, fade=self.gauge_fade_in.attribute)
else: else:
tex.draw_texture('gauge', 'clear_dark', scale=scale, color=color) tex.draw_texture('gauge', 'clear_dark', scale=scale, fade=self.gauge_fade_in.attribute)
tex.draw_texture('gauge', 'tamashii_dark', scale=scale, color=color) tex.draw_texture('gauge', 'tamashii_dark', scale=scale, fade=self.gauge_fade_in.attribute)

View File

@@ -25,7 +25,6 @@ class SettingsScreen:
self.in_setting_edit = False self.in_setting_edit = False
self.editing_key = False self.editing_key = False
self.editing_gamepad = False self.editing_gamepad = False
self.temp_key_input = ""
def on_screen_start(self): def on_screen_start(self):
if not self.screen_init: if not self.screen_init:
@@ -109,7 +108,6 @@ class SettingsScreen:
def handle_key_binding(self, section, key): def handle_key_binding(self, section, key):
"""Handle key binding changes""" """Handle key binding changes"""
self.editing_key = True self.editing_key = True
self.temp_key_input = ""
def update_key_binding(self): def update_key_binding(self):
"""Update key binding based on input""" """Update key binding based on input"""
@@ -129,7 +127,6 @@ class SettingsScreen:
def handle_gamepad_binding(self, section, key): def handle_gamepad_binding(self, section, key):
self.editing_gamepad = True self.editing_gamepad = True
self.temp_key_input = ""
def update_gamepad_binding(self): def update_gamepad_binding(self):
"""Update gamepad binding based on input""" """Update gamepad binding based on input"""

View File

@@ -63,7 +63,6 @@ class SongSelectScreen:
self.game_transition = None self.game_transition = None
self.texture_index = 9 self.texture_index = 9
self.last_texture_index = 9 self.last_texture_index = 9
self.default_texture = self.texture_index
self.demo_song = None self.demo_song = None
self.navigator.reset_items() self.navigator.reset_items()
self.navigator.get_current_item().box.get_scores() self.navigator.get_current_item().box.get_scores()
@@ -297,8 +296,7 @@ class SongSelectScreen:
width = tex.textures['box']['background'].width width = tex.textures['box']['background'].width
for i in range(0, width * 4, width): for i in range(0, width * 4, width):
tex.draw_texture('box', 'background', frame=self.last_texture_index, x=i - int(self.background_move.attribute)) tex.draw_texture('box', 'background', frame=self.last_texture_index, x=i - int(self.background_move.attribute))
reverse_color = ray.fade(ray.WHITE, 1 - self.background_fade_change.attribute) tex.draw_texture('box', 'background', frame=self.texture_index, x=i - int(self.background_move.attribute), fade=1 - self.background_fade_change.attribute)
tex.draw_texture('box', 'background', frame=self.texture_index, x=i - int(self.background_move.attribute), color=reverse_color)
if self.navigator.genre_bg is not None and self.state == State.BROWSING: if self.navigator.genre_bg is not None and self.state == State.BROWSING:
self.navigator.genre_bg.draw(95) self.navigator.genre_bg.draw(95)
@@ -314,11 +312,9 @@ class SongSelectScreen:
if self.selected_song and self.state == State.SONG_SELECTED: if self.selected_song and self.state == State.SONG_SELECTED:
self.draw_selector() self.draw_selector()
fade = ray.fade(ray.WHITE, self.text_fade_in.attribute) tex.draw_texture('global', 'difficulty_select', fade=self.text_fade_in.attribute)
tex.draw_texture('global', 'difficulty_select', color=fade)
else: else:
fade = ray.fade(ray.WHITE, self.text_fade_out.attribute) tex.draw_texture('global', 'song_select', fade=self.text_fade_out.attribute)
tex.draw_texture('global', 'song_select', color=fade)
tex.draw_texture('global', 'footer') tex.draw_texture('global', 'footer')
@@ -365,9 +361,6 @@ class SongBox:
self.move = None self.move = None
self.wait = 0 self.wait = 0
self.is_dir = is_dir self.is_dir = is_dir
self.is_genre_start = 0
self.is_genre_end = False
self.genre_distance = 0
self.tja_count = tja_count self.tja_count = tja_count
self.tja_count_text = None self.tja_count_text = None
self.tja = tja self.tja = tja
@@ -642,7 +635,7 @@ class YellowBox:
tex.draw_texture('yellow_box', 's_crown_fc', x=(diff*60), color=color) tex.draw_texture('yellow_box', 's_crown_fc', x=(diff*60), color=color)
elif diff in song_box.scores and song_box.scores[diff] is not None and song_box.scores[diff][4] == 1: elif diff in song_box.scores and song_box.scores[diff] is not None and song_box.scores[diff][4] == 1:
tex.draw_texture('yellow_box', 's_crown_clear', x=(diff*60), color=color) tex.draw_texture('yellow_box', 's_crown_clear', x=(diff*60), color=color)
tex.draw_texture('yellow_box', 's_crown_outline', x=(diff*60), color=ray.fade(ray.WHITE, min(fade, 0.25))) tex.draw_texture('yellow_box', 's_crown_outline', x=(diff*60), fade=min(fade, 0.25))
if self.tja.ex_data.new_audio: if self.tja.ex_data.new_audio:
tex.draw_texture('yellow_box', 'ex_data_new_audio', color=color) tex.draw_texture('yellow_box', 'ex_data_new_audio', color=color)
@@ -656,7 +649,7 @@ class YellowBox:
for i in range(4): for i in range(4):
tex.draw_texture('yellow_box', 'difficulty_bar', frame=i, x=(i*60), color=color) tex.draw_texture('yellow_box', 'difficulty_bar', frame=i, x=(i*60), color=color)
if i not in self.tja.metadata.course_data: if i not in self.tja.metadata.course_data:
tex.draw_texture('yellow_box', 'difficulty_bar_shadow', frame=i, x=(i*60), color=ray.fade(ray.WHITE, min(fade, 0.25))) tex.draw_texture('yellow_box', 'difficulty_bar_shadow', frame=i, x=(i*60), fade=min(fade, 0.25))
for diff in self.tja.metadata.course_data: for diff in self.tja.metadata.course_data:
if diff >= 4: if diff >= 4:
@@ -667,23 +660,22 @@ class YellowBox:
def _draw_tja_data_diff(self, is_ura: bool): def _draw_tja_data_diff(self, is_ura: bool):
if self.tja is None: if self.tja is None:
return return
color = ray.fade(ray.WHITE, self.fade_in.attribute) tex.draw_texture('diff_select', 'back', fade=self.fade_in.attribute)
tex.draw_texture('diff_select', 'back', color=color)
for i in range(4): for i in range(4):
if i == 3 and is_ura: if i == 3 and is_ura:
tex.draw_texture('diff_select', 'diff_tower', frame=4, x=(i*115), color=color) tex.draw_texture('diff_select', 'diff_tower', frame=4, x=(i*115), fade=self.fade_in.attribute)
tex.draw_texture('diff_select', 'ura_oni_plate', color=color) tex.draw_texture('diff_select', 'ura_oni_plate', fade=self.fade_in.attribute)
else: else:
tex.draw_texture('diff_select', 'diff_tower', frame=i, x=(i*115), color=color) tex.draw_texture('diff_select', 'diff_tower', frame=i, x=(i*115), fade=self.fade_in.attribute)
if i not in self.tja.metadata.course_data: if i not in self.tja.metadata.course_data:
tex.draw_texture('diff_select', 'diff_tower_shadow', frame=i, x=(i*115), color=ray.fade(ray.WHITE, min(self.fade_in.attribute, 0.25))) tex.draw_texture('diff_select', 'diff_tower_shadow', frame=i, x=(i*115), fade=min(self.fade_in.attribute, 0.25))
for course in self.tja.metadata.course_data: for course in self.tja.metadata.course_data:
if (course == 4 and not is_ura) or (course == 3 and is_ura): if (course == 4 and not is_ura) or (course == 3 and is_ura):
continue continue
for j in range(self.tja.metadata.course_data[course].level): for j in range(self.tja.metadata.course_data[course].level):
tex.draw_texture('yellow_box', 'star_ura', x=min(course, 3)*115, y=(j*-20), color=color) tex.draw_texture('yellow_box', 'star_ura', x=min(course, 3)*115, y=(j*-20), fade=self.fade_in.attribute)
def _draw_text(self, song_box): def _draw_text(self, song_box):
if not isinstance(self.right_out, MoveAnimation): if not isinstance(self.right_out, MoveAnimation):
@@ -724,10 +716,9 @@ class YellowBox:
fade = self.fade.attribute fade = self.fade.attribute
if fade_override is not None: if fade_override is not None:
fade = min(self.fade.attribute, fade_override) fade = min(self.fade.attribute, fade_override)
color = ray.fade(ray.WHITE, fade)
if self.is_back: if self.is_back:
tex.draw_texture('box', 'back_graphic', color=color) tex.draw_texture('box', 'back_graphic', fade=fade)
self._draw_tja_data(song_box, color, fade) self._draw_tja_data(song_box, ray.fade(ray.WHITE, fade), fade)
self._draw_text(song_box) self._draw_text(song_box)
@@ -745,10 +736,9 @@ class GenreBG:
self.end_position = self.end_box.position self.end_position = self.end_box.position
self.fade_in.update(current_ms) self.fade_in.update(current_ms)
def draw(self, y): def draw(self, y):
color = ray.fade(ray.WHITE, self.fade_in.attribute)
offset = -150 if self.start_box.is_open else 0 offset = -150 if self.start_box.is_open else 0
tex.draw_texture('box', 'folder_background_edge', frame=self.end_box.texture_index, x=self.start_position+offset, y=y, mirror="horizontal", color=color) tex.draw_texture('box', 'folder_background_edge', frame=self.end_box.texture_index, x=self.start_position+offset, y=y, mirror="horizontal", fade=self.fade_in.attribute)
extra_distance = 155 if self.end_box.is_open or self.start_box.is_open else 0 extra_distance = 155 if self.end_box.is_open or self.start_box.is_open else 0
if self.start_position >= -56 and self.end_position < self.start_position: if self.start_position >= -56 and self.end_position < self.start_position:
x2 = self.start_position + 1336 x2 = self.start_position + 1336
@@ -759,16 +749,16 @@ class GenreBG:
x2 = min(self.end_position+75, 1280) + extra_distance x2 = min(self.end_position+75, 1280) + extra_distance
tex.draw_texture('box', 'folder_background', x=-18, y=y, x2=x2, frame=self.end_box.texture_index) tex.draw_texture('box', 'folder_background', x=-18, y=y, x2=x2, frame=self.end_box.texture_index)
offset = 150 if self.end_box.is_open else 0 offset = 150 if self.end_box.is_open else 0
tex.draw_texture('box', 'folder_background_edge', x=self.end_position+80+offset, y=y, color=color, frame=self.end_box.texture_index) tex.draw_texture('box', 'folder_background_edge', x=self.end_position+80+offset, y=y, fade=self.fade_in.attribute, frame=self.end_box.texture_index)
if ((self.start_position <= 594 and self.end_position >= 594) or if ((self.start_position <= 594 and self.end_position >= 594) or
((self.start_position <= 594 or self.end_position >= 594) and (self.start_position > self.end_position))): ((self.start_position <= 594 or self.end_position >= 594) and (self.start_position > self.end_position))):
dest_width = min(300, self.title.texture.width) dest_width = min(300, self.title.texture.width)
tex.draw_texture('box', 'folder_header', x=-(dest_width//2), y=y, x2=dest_width, color=color, frame=self.end_box.texture_index) tex.draw_texture('box', 'folder_header', x=-(dest_width//2), y=y, x2=dest_width, fade=self.fade_in.attribute, frame=self.end_box.texture_index)
tex.draw_texture('box', 'folder_header_edge', x=-(dest_width//2), y=y, color=color, frame=self.end_box.texture_index, mirror="horizontal") tex.draw_texture('box', 'folder_header_edge', x=-(dest_width//2), y=y, fade=self.fade_in.attribute, frame=self.end_box.texture_index, mirror="horizontal")
tex.draw_texture('box', 'folder_header_edge', x=(dest_width//2), y=y, color=color, frame=self.end_box.texture_index) tex.draw_texture('box', 'folder_header_edge', x=(dest_width//2), y=y, fade=self.fade_in.attribute, frame=self.end_box.texture_index)
dest = ray.Rectangle((1280//2) - (dest_width//2), y-60, dest_width, self.title.texture.height) dest = ray.Rectangle((1280//2) - (dest_width//2), y-60, dest_width, self.title.texture.height)
self.title.draw(self.title.default_src, dest, ray.Vector2(0, 0), 0, color) self.title.draw(self.title.default_src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, self.fade_in.attribute))
class UraSwitchAnimation: class UraSwitchAnimation:
def __init__(self) -> None: def __init__(self) -> None:
@@ -785,7 +775,7 @@ class UraSwitchAnimation:
self.texture_change.update(current_ms) self.texture_change.update(current_ms)
self.fade_out.update(current_ms) self.fade_out.update(current_ms)
def draw(self): def draw(self):
tex.draw_texture('diff_select', 'ura_switch', frame=self.texture_change.attribute, color=ray.fade(ray.WHITE, self.fade_out.attribute)) tex.draw_texture('diff_select', 'ura_switch', frame=self.texture_change.attribute, fade=self.fade_out.attribute)
class FileSystemItem: class FileSystemItem:
GENRE_MAP = { GENRE_MAP = {
@@ -801,7 +791,6 @@ class FileSystemItem:
"""Base class for files and directories in the navigation system""" """Base class for files and directories in the navigation system"""
def __init__(self, path: Path, name: str): def __init__(self, path: Path, name: str):
self.path = path self.path = path
self.selected = False
class Directory(FileSystemItem): class Directory(FileSystemItem):
"""Represents a directory in the navigation system""" """Represents a directory in the navigation system"""
@@ -1188,10 +1177,6 @@ class FileNavigator:
else: else:
item.box.target_position = position item.box.target_position = position
def set_base_positions(self):
"""Set initial positions for all items"""
self.calculate_box_positions()
def load_root_directories(self): def load_root_directories(self):
"""Load the pre-generated root directory items""" """Load the pre-generated root directory items"""
self.items = self.root_items.copy() self.items = self.root_items.copy()
@@ -1338,24 +1323,3 @@ class FileNavigator:
def reset_items(self): def reset_items(self):
for item in self.items: for item in self.items:
item.box.reset() item.box.reset()
def regenerate_objects(self):
"""Regenerate all objects (useful if files have changed on disk)"""
print("Regenerating all objects...")
# Clear existing objects
self.all_directories.clear()
self.all_song_files.clear()
self.directory_contents.clear()
self.root_items.clear()
self.directory_crowns.clear() # Clear crown cache
self.crown_cache_dirty.clear() # Clear dirty flags
# Regenerate everything
self._generate_all_objects()
# Reset navigation state
self.current_dir = Path()
self.current_root_dir = Path()
self.history.clear()
self.load_root_directories()

View File

@@ -1,8 +1,6 @@
import random import random
from pathlib import Path from pathlib import Path
import pyray as ray
from libs.audio import audio from libs.audio import audio
from libs.texture import tex from libs.texture import tex
from libs.utils import ( from libs.utils import (
@@ -108,7 +106,7 @@ class TitleScreen:
elif self.state == State.ATTRACT_VIDEO and self.attract_video is not None: elif self.state == State.ATTRACT_VIDEO and self.attract_video is not None:
self.attract_video.draw() self.attract_video.draw()
tex.draw_texture('movie', 'background', color=ray.fade(ray.WHITE, self.fade_out.attribute)) tex.draw_texture('movie', 'background', fade=self.fade_out.attribute)
def draw_3d(self): def draw_3d(self):
pass pass
@@ -134,10 +132,10 @@ class WarningScreen:
self.sound_played = True self.sound_played = True
def draw_bg(self): def draw_bg(self):
tex.draw_texture('warning', 'x_lightred', color=ray.fade(ray.WHITE, self.fadein_2.attribute)) tex.draw_texture('warning', 'x_lightred', fade=self.fadein_2.attribute)
def draw_fg(self): def draw_fg(self):
tex.draw_texture('warning', 'x_red', color=ray.fade(ray.WHITE, self.fadein.attribute), scale=self.resize.attribute, center=True) tex.draw_texture('warning', 'x_red', fade=self.fadein.attribute, scale=self.resize.attribute, center=True)
class BachiHit: class BachiHit:
def __init__(self): def __init__(self):
@@ -156,7 +154,7 @@ class WarningScreen:
self.fadein.update(current_ms) self.fadein.update(current_ms)
def draw(self): def draw(self):
tex.draw_texture('warning', 'bachi_hit', color=ray.fade(ray.WHITE, self.fadein.attribute), scale=self.resize.attribute, center=True) tex.draw_texture('warning', 'bachi_hit', fade=self.fadein.attribute, scale=self.resize.attribute, center=True)
if self.resize.attribute > 0 and self.sound_played: if self.resize.attribute > 0 and self.sound_played:
tex.draw_texture('warning', 'bachi') tex.draw_texture('warning', 'bachi')
@@ -182,14 +180,14 @@ class WarningScreen:
else: else:
self.shadow_fade.restart() self.shadow_fade.restart()
self.is_finished = self.chara_1_frame.is_finished self.is_finished = self.chara_1_frame.is_finished
def draw(self, fade: ray.Color, fade_2: ray.Color): def draw(self, fade: float, fade_2: float):
tex.draw_texture('warning', 'chara_0_shadow', color=fade_2) tex.draw_texture('warning', 'chara_0_shadow', fade=fade_2)
tex.draw_texture('warning', 'chara_0', frame=self.chara_0_frame.attribute, color=fade) tex.draw_texture('warning', 'chara_0', frame=self.chara_0_frame.attribute, fade=fade)
tex.draw_texture('warning', 'chara_1_shadow', color=fade_2) tex.draw_texture('warning', 'chara_1_shadow', fade=fade_2)
if -1 < self.chara_1_frame.attribute-1 < 7: if -1 < self.chara_1_frame.attribute-1 < 7:
tex.draw_texture('warning', 'chara_1', frame=self.chara_1_frame.attribute-1, color=ray.fade(ray.WHITE, self.shadow_fade.attribute)) tex.draw_texture('warning', 'chara_1', frame=self.chara_1_frame.attribute-1, fade=self.shadow_fade.attribute)
tex.draw_texture('warning', 'chara_1', frame=self.chara_1_frame.attribute, color=fade) tex.draw_texture('warning', 'chara_1', frame=self.chara_1_frame.attribute, fade=fade)
class Board: class Board:
def __init__(self): def __init__(self):
@@ -256,13 +254,10 @@ class WarningScreen:
self.is_finished = self.fade_out.is_finished self.is_finished = self.fade_out.is_finished
def draw(self): def draw(self):
fade = ray.fade(ray.WHITE, self.fade_in.attribute)
fade_2 = ray.fade(ray.WHITE, min(self.fade_in.attribute, 0.75))
self.board.draw() self.board.draw()
self.warning_x.draw_bg() self.warning_x.draw_bg()
self.characters.draw(fade, fade_2) self.characters.draw(self.fade_in.attribute, min(self.fade_in.attribute, 0.75))
self.warning_x.draw_fg() self.warning_x.draw_fg()
self.warning_bachi_hit.draw() self.warning_bachi_hit.draw()
tex.draw_texture('movie', 'background', color=ray.fade(ray.WHITE, self.fade_out.attribute)) tex.draw_texture('movie', 'background', fade=self.fade_out.attribute)

3
uv.lock generated
View File

@@ -314,9 +314,6 @@ requires-dist = [
{ name = "tomlkit", specifier = ">=0.13.3" }, { name = "tomlkit", specifier = ">=0.13.3" },
] ]
[package.metadata.requires-dev]
dev = []
[[package]] [[package]]
name = "python-dotenv" name = "python-dotenv"
version = "1.1.0" version = "1.1.0"