finally refactor the song select boxes

This commit is contained in:
Anthony Samms
2025-11-19 18:35:26 -05:00
parent 24e0c8d980
commit 802d9c5b37
14 changed files with 401 additions and 387 deletions

View File

@@ -4,14 +4,14 @@ import pyray as ray
from libs.audio import audio
from libs.global_data import PlayerNum, global_data
from libs.texture import tex
from libs.texture import SCREEN_HEIGHT, SCREEN_WIDTH, tex
from libs.chara_2d import Chara2D
from libs.global_objects import AllNetIcon, CoinOverlay, Indicator, Nameplate, Timer
from libs.screen import Screen
from libs.file_navigator import DanCourse, navigator
from libs.file_navigator import BackBox, DanCourse, navigator
from libs.transition import Transition
from libs.utils import get_current_ms, is_l_don_pressed, is_l_kat_pressed, is_r_don_pressed, is_r_kat_pressed
from scenes.song_select import SongSelectScreen, State
from scenes.song_select import State
logger = logging.getLogger(__name__)
@@ -35,7 +35,7 @@ class DanSelectScreen(Screen):
session_data = global_data.session_data[global_data.player_num]
current_item = self.navigator.get_current_item()
if isinstance(current_item, DanCourse):
session_data.selected_song = current_item.charts[0]
session_data.selected_song = current_item.charts[0][0].file_path
session_data.selected_dan = current_item.charts
session_data.selected_dan_exam = current_item.exams
session_data.song_title = current_item.title
@@ -88,8 +88,9 @@ class DanSelectScreen(Screen):
if self.transition.is_finished:
return self.on_screen_end("GAME_DAN")
for song in self.navigator.items:
song.box.update(False)
song.box.is_open = song.box.position == SongSelectScreen.BOX_CENTER + 150
if not song.box.text_loaded:
song.box.load_text()
song.box.update(current_time, False)
self.player.update(current_time)
res = self.handle_input(self.state, self)
if res == 'go_back':
@@ -102,13 +103,13 @@ class DanSelectScreen(Screen):
tex.draw_texture('global', 'footer')
for item in self.navigator.items:
box = item.box
if -156 <= box.position <= 1280 + 144:
if -156 <= box.position <= SCREEN_WIDTH + 144:
if box.position <= 500:
box.draw(box.position, 95, False)
else:
box.draw(box.position, 95, False)
if self.state == State.SONG_SELECTED:
ray.draw_rectangle(0, 0, 1280, 720, ray.fade(ray.BLACK, min(0.5, self.player.confirmation_window.fade_in.attribute)))
ray.draw_rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ray.fade(ray.BLACK, min(0.5, self.player.confirmation_window.fade_in.attribute)))
self.player.draw()
self.indicator.draw(410, 575)
self.timer.draw()
@@ -169,7 +170,7 @@ class DanSelectPlayer:
# Select/Enter
if is_l_don_pressed(self.player_num) or is_r_don_pressed(self.player_num):
if selected_item is not None and selected_item.box.is_back:
if selected_item is not None and isinstance(selected_item.box, BackBox):
audio.play_sound('cancel', 'sound')
return "go_back"
else:

View File

@@ -185,7 +185,10 @@ class DanGameScreen(GameScreen):
self.transition.update(current_time)
self.current_ms = current_time - self.start_ms
self.dan_transition.update(current_time)
self.start_song(current_time)
if self.transition.is_finished and self.dan_transition.is_finished:
self.start_song(self.current_ms)
else:
self.start_ms = current_time - self.tja.metadata.offset*1000
self.update_background(current_time)
if self.song_music is not None:

View File

@@ -104,7 +104,7 @@ class EntryScreen(Screen):
self.state = State.SELECT_SIDE
plate_info = global_data.config['nameplate_2p']
self.nameplate = Nameplate(plate_info['name'], plate_info['title'], PlayerNum.ALL, -1, False, False, 1)
self.chara = Chara2D(1, 100)
self.chara = Chara2D(1)
self.side_select_fade.restart()
self.side = 1
elif self.players[0] and self.players[0].player_num == PlayerNum.P2 and is_l_don_pressed(PlayerNum.P1) or is_r_don_pressed(PlayerNum.P1):
@@ -291,19 +291,19 @@ class EntryPlayer:
move_y = self.drum_move_1.attribute + self.drum_move_2.attribute
if self.side == 0: # Left side (1P/red)
offset = 0
offset = tex.skin_config["entry_drum_offset"].x
tex.draw_texture('side_select', 'red_drum', x=move_x, y=move_y)
chara_x = move_x + offset + 170
chara_x = move_x + offset + tex.skin_config["entry_chara_offset_l"].x
chara_mirror = False
else: # Right side (2P/blue)
move_x *= -1
offset = 620
offset = tex.skin_config["entry_drum_offset"].y # bad practice to use y value as x value
tex.draw_texture('side_select', 'blue_drum', x=move_x, y=move_y)
chara_x = move_x + offset + 130
chara_x = move_x + offset + tex.skin_config["entry_chara_offset_r"].x
chara_mirror = True
# Draw character
chara_y = 570 + move_y
chara_y = tex.skin_config["entry_chara_offset_r"].y + move_y
self.chara.draw(chara_x, chara_y, mirror=chara_mirror)
# Draw cloud
@@ -414,7 +414,7 @@ class Box:
texture_left = tex.textures['mode_select']['box_highlight_left'].texture
if isinstance(texture_left, list):
raise Exception("highlight textures cannot be iterable")
tex.draw_texture('mode_select', 'box_highlight_center', x=self.left_x + texture_left.width, y=self.y, x2=self.right_x - self.left_x -15, color=color)
tex.draw_texture('mode_select', 'box_highlight_center', x=self.left_x + texture_left.width, y=self.y, x2=self.right_x - self.left_x + tex.skin_config["entry_box_highlight_offset"].x, color=color)
tex.draw_texture('mode_select', 'box_highlight_left', x=self.left_x, y=self.y, color=color)
tex.draw_texture('mode_select', 'box_highlight_right', x=self.right_x, y=self.y, color=color)
@@ -422,7 +422,7 @@ class Box:
text_x = self.x + (self.texture.width//2) - (self.text.texture.width//2)
if self.is_selected:
text_x += self.open.attribute
text_y = self.y + 20
text_y = self.y + tex.skin_config["entry_box_text_offset"].y
if self.is_selected:
self.text.draw(outline_color=ray.BLACK, x=text_x, y=text_y, color=color)
else:
@@ -430,7 +430,7 @@ class Box:
def draw(self, fade: float):
color = ray.fade(ray.WHITE, fade)
ray.draw_texture(self.texture, self.x, self.y, color)
ray.draw_texture(self.texture, int(self.x), int(self.y), color)
if self.is_selected and self.move.is_finished:
self._draw_highlighted(color)
self._draw_text(color)
@@ -439,9 +439,9 @@ class BoxManager:
"""BoxManager class for the entry screen"""
def __init__(self):
self.box_titles: list[OutlinedText] = [
OutlinedText('演奏ゲーム', 50, ray.WHITE, outline_thickness=5, vertical=True),
OutlinedText('特訓モード', 50, ray.WHITE, outline_thickness=5, vertical=True),
OutlinedText('ゲーム設定', 50, ray.WHITE, outline_thickness=5, vertical=True)]
OutlinedText('演奏ゲーム', tex.skin_config["entry_box_text"].font_size, ray.WHITE, outline_thickness=5, vertical=True),
OutlinedText('特訓モード', tex.skin_config["entry_box_text"].font_size, ray.WHITE, outline_thickness=5, vertical=True),
OutlinedText('ゲーム設定', tex.skin_config["entry_box_text"].font_size, ray.WHITE, outline_thickness=5, vertical=True)]
self.box_locations = ["SONG_SELECT", "PRACTICE_SELECT", "SETTINGS"]
self.num_boxes = len(self.box_titles)
self.boxes = [Box(self.box_titles[i], self.box_locations[i]) for i in range(len(self.box_titles))]
@@ -449,7 +449,7 @@ class BoxManager:
self.fade_out = tex.get_animation(9)
self.is_2p = False
spacing = 80
spacing = tex.skin_config["entry_box_spacing"].x
box_width = self.boxes[0].texture.width
total_width = self.num_boxes * box_width + (self.num_boxes - 1) * spacing
start_x = SCREEN_WIDTH//2 - total_width//2

View File

@@ -7,7 +7,7 @@ from libs.animation import Animation
from libs.global_objects import AllNetIcon
from libs.screen import Screen
from libs.song_hash import build_song_hashes
from libs.texture import tex
from libs.texture import SCREEN_HEIGHT, SCREEN_WIDTH, tex
from libs.utils import get_current_ms, global_data
from libs.file_navigator import navigator
@@ -17,8 +17,8 @@ logger = logging.getLogger(__name__)
class LoadScreen(Screen):
def __init__(self, name: str):
super().__init__(name)
self.width = 1280
self.height = 720
self.width = SCREEN_WIDTH
self.height = SCREEN_HEIGHT
self.songs_loaded = False
self.navigator_started = False
self.loading_complete = False

View File

@@ -5,7 +5,7 @@ from pathlib import Path
import pyray as ray
import logging
from libs.file_navigator import DanCourse, navigator
from libs.file_navigator import BackBox, DanCourse, navigator
from libs.audio import audio
from libs.chara_2d import Chara2D
from libs.file_navigator import Directory, SongBox, SongFile
@@ -79,21 +79,23 @@ class SongSelectScreen(Screen):
self.navigator.mark_crowns_dirty_for_song(selected_song)
curr_item = self.navigator.get_current_item()
curr_item.box.get_scores()
if isinstance(curr_item, SongFile):
curr_item.box.get_scores()
self.navigator.add_recent()
def finalize_song(self):
global_data.session_data[global_data.player_num].selected_song = self.navigator.get_current_item().path
def finalize_song(self, current_item: SongFile):
global_data.session_data[global_data.player_num].selected_song = current_item.path
global_data.session_data[global_data.player_num].selected_difficulty = self.player_1.selected_difficulty
global_data.session_data[global_data.player_num].genre_index = self.navigator.get_current_item().box.name_texture_index
global_data.session_data[global_data.player_num].genre_index = current_item.box.name_texture_index
def on_screen_end(self, next_screen):
self.screen_init = False
self.reset_demo_music()
self.finalize_song()
self.player_1.nameplate.unload()
current_item = self.navigator.get_current_item()
if current_item.box.yellow_box is not None:
if isinstance(current_item, SongFile):
self.finalize_song(current_item)
self.player_1.nameplate.unload()
if isinstance(current_item.box, SongBox) and current_item.box.yellow_box is not None:
current_item.box.yellow_box.create_anim()
return super().on_screen_end(next_screen)
@@ -156,6 +158,8 @@ class SongSelectScreen(Screen):
elif action == "add_favorite":
self.navigator.add_favorite()
current_box = self.navigator.get_current_item().box
if not isinstance(current_box, SongBox):
return
current_box.is_favorite = not current_box.is_favorite
def handle_input_selected(self):
@@ -281,18 +285,19 @@ class SongSelectScreen(Screen):
audio.update_music_stream(self.demo_song)
if self.navigator.genre_bg is not None:
self.navigator.genre_bg.update(get_current_ms())
self.navigator.genre_bg.update(current_time)
if self.diff_sort_selector is not None:
self.diff_sort_selector.update(get_current_ms())
self.diff_sort_selector.update(current_time)
self.check_for_selection()
for song in self.navigator.items:
song.box.update(self.state == State.SONG_SELECTED)
song.box.is_open = song.box.position == SongSelectScreen.BOX_CENTER + 150
song.box.update(current_time, self.state == State.SONG_SELECTED)
if not song.box.text_loaded:
song.box.load_text()
if not isinstance(song, Directory) and song.box.is_open:
if self.demo_song is None and get_current_ms() >= song.box.wait + (83.33*3):
if self.demo_song is None and current_time >= song.box.wait + (83.33*3):
song.box.get_scores()
if song.tja.metadata.wave.exists() and song.tja.metadata.wave.is_file():
self.demo_song = audio.load_music_stream(song.tja.metadata.wave, 'demo_song')
@@ -302,7 +307,7 @@ class SongSelectScreen(Screen):
logger.info(f"Demo song loaded and playing for {song.tja.metadata.title}")
if song.box.is_open:
current_box = song.box
if not current_box.is_back and get_current_ms() >= song.box.wait + (83.33*3):
if not isinstance(current_box, BackBox) and current_time >= song.box.wait + (83.33*3):
self.texture_index = current_box.texture_index
if ray.is_key_pressed(global_data.config["keys"]["back_key"]):
@@ -326,7 +331,7 @@ class SongSelectScreen(Screen):
if self.navigator.genre_bg is not None and self.state == State.BROWSING:
self.navigator.genre_bg.draw(95)
for item in self.navigator.items:
for i, item in enumerate(self.navigator.items):
box = item.box
if -156 <= box.position <= SCREEN_WIDTH + 144:
if box.position <= 500:
@@ -354,7 +359,9 @@ class SongSelectScreen(Screen):
self.draw_players()
if self.state == State.BROWSING and self.navigator.items != []:
self.navigator.get_current_item().box.draw_score_history()
curr_item = self.navigator.get_current_item()
if isinstance(curr_item, SongFile):
curr_item.box.draw_score_history()
self.indicator.draw(410, 575)
@@ -461,7 +468,7 @@ class SongSelectPlayer:
# Select/Enter
if is_l_don_pressed(self.player_num) or is_r_don_pressed(self.player_num):
if selected_item is not None and selected_item.box.is_back:
if selected_item is not None and isinstance(selected_item.box, BackBox):
audio.play_sound('cancel', 'sound')
return "go_back"
elif isinstance(selected_item, Directory) and selected_item.collection == Directory.COLLECTIONS[3]:

View File

@@ -1,5 +1,5 @@
import logging
from libs.file_navigator import SongFile
from libs.file_navigator import SongBox, SongFile
from libs.global_data import PlayerNum
from libs.transition import Transition
from scenes.song_select import DiffSortSelect, SongSelectPlayer, SongSelectScreen, State
@@ -14,9 +14,9 @@ class TwoPlayerSongSelectScreen(SongSelectScreen):
self.player_1 = SongSelectPlayer(PlayerNum.P1, self.text_fade_in)
self.player_2 = SongSelectPlayer(PlayerNum.P2, self.text_fade_in)
def finalize_song(self):
global_data.session_data[PlayerNum.P1].selected_song = self.navigator.get_current_item().path
global_data.session_data[PlayerNum.P1].genre_index = self.navigator.get_current_item().box.name_texture_index
def finalize_song(self, current_item):
global_data.session_data[PlayerNum.P1].selected_song = current_item.path
global_data.session_data[PlayerNum.P1].genre_index = current_item.box.name_texture_index
logger.info(f"Finalized song selection: {global_data.session_data[PlayerNum.P1].selected_song}")
def handle_input(self):
@@ -81,6 +81,8 @@ class TwoPlayerSongSelectScreen(SongSelectScreen):
elif action == "add_favorite":
self.navigator.add_favorite()
current_box = self.navigator.get_current_item().box
if not isinstance(current_box, SongBox):
return
current_box.is_favorite = not current_box.is_favorite
def handle_input_selected(self):