fixed drawing

This commit is contained in:
Anthony Samms
2025-11-10 16:33:21 -05:00
parent a1b1471bd5
commit 1a69fbfbf0
2 changed files with 132 additions and 80 deletions

View File

@@ -1071,32 +1071,7 @@ class Player:
for modifier in modifiers_to_draw: for modifier in modifiers_to_draw:
tex.draw_texture('lane', modifier, index=self.is_2p) tex.draw_texture('lane', modifier, index=self.is_2p)
def draw_note_types(self, ms_from_start: float, start_ms: float): def draw_overlays(self, mask_shader: ray.Shader):
self.draw_bars(ms_from_start)
self.draw_notes(ms_from_start, start_ms)
def draw(self, ms_from_start: float, start_ms: float, mask_shader: ray.Shader, dan_transition = None):
# Group 1: Background and lane elements
tex.draw_texture('lane', 'lane_background', index=self.is_2p)
if self.branch_indicator is not None:
self.branch_indicator.draw()
if self.gauge is not None:
self.gauge.draw()
if self.lane_hit_effect is not None:
self.lane_hit_effect.draw()
tex.draw_texture('lane', 'lane_hit_circle', index=self.is_2p)
# Group 2: Judgement and hit effects
if self.gogo_time is not None:
self.gogo_time.draw()
for anim in self.draw_judge_list:
anim.draw()
# Group 3: Notes and bars (game content)
self.draw_note_types(ms_from_start, start_ms)
if dan_transition is not None:
dan_transition.draw()
# Group 4: Lane covers and UI elements (batch similar textures) # Group 4: Lane covers and UI elements (batch similar textures)
tex.draw_texture('lane', f'{self.player_number}p_lane_cover', index=self.is_2p) tex.draw_texture('lane', f'{self.player_number}p_lane_cover', index=self.is_2p)
if self.is_dan: if self.is_dan:
@@ -1151,6 +1126,31 @@ class Player:
anim.draw() anim.draw()
#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(self, ms_from_start: float, start_ms: float, mask_shader: ray.Shader, dan_transition = None):
# Group 1: Background and lane elements
tex.draw_texture('lane', 'lane_background', index=self.is_2p)
if self.branch_indicator is not None:
self.branch_indicator.draw()
if self.gauge is not None:
self.gauge.draw()
if self.lane_hit_effect is not None:
self.lane_hit_effect.draw()
tex.draw_texture('lane', 'lane_hit_circle', index=self.is_2p)
# Group 2: Judgement and hit effects
if self.gogo_time is not None:
self.gogo_time.draw()
for anim in self.draw_judge_list:
anim.draw()
# Group 3: Notes and bars (game content)
self.draw_bars(ms_from_start)
self.draw_notes(ms_from_start, start_ms)
if dan_transition is not None:
dan_transition.draw()
self.draw_overlays(mask_shader)
class Judgement: class Judgement:
"""Shows the judgement of the player's hit""" """Shows the judgement of the player's hit"""
def __init__(self, type: str, big: bool, is_2p: bool): def __init__(self, type: str, big: bool, is_2p: bool):

View File

@@ -10,7 +10,7 @@ from libs.audio import audio
from libs.background import Background from libs.background import Background
from libs.global_data import Modifiers, global_data from libs.global_data import Modifiers, global_data
from libs.tja import Balloon, Drumroll, TJAParser, apply_modifiers from libs.tja import Balloon, Drumroll, TJAParser, apply_modifiers
from libs.utils import get_current_ms from libs.utils import get_current_ms, get_key_code
from libs.texture import tex from libs.texture import tex
from scenes.game import GameScreen, JudgeCounter, Player, SCREEN_WIDTH from scenes.game import GameScreen, JudgeCounter, Player, SCREEN_WIDTH
@@ -24,13 +24,13 @@ class PracticeGameScreen(GameScreen):
def init_tja(self, song: Path): def init_tja(self, song: Path):
"""Initialize the TJA file""" """Initialize the TJA file"""
self.tja = TJAParser(song, start_delay=self.start_delay, distance=SCREEN_WIDTH - GameScreen.JUDGE_X) self.tja = TJAParser(song, start_delay=self.start_delay, distance=SCREEN_WIDTH - GameScreen.JUDGE_X)
self.scrolling_tja = TJAParser(song, start_delay=self.start_delay, distance=SCREEN_WIDTH - GameScreen.JUDGE_X) self.scrobbling_tja = TJAParser(song, start_delay=self.start_delay, distance=SCREEN_WIDTH - GameScreen.JUDGE_X)
global_data.session_data[0].song_title = self.tja.metadata.title.get(global_data.config['general']['language'].lower(), self.tja.metadata.title['en']) global_data.session_data[0].song_title = self.tja.metadata.title.get(global_data.config['general']['language'].lower(), self.tja.metadata.title['en'])
if self.tja.metadata.wave.exists() and self.tja.metadata.wave.is_file() and self.song_music is None: if self.tja.metadata.wave.exists() and self.tja.metadata.wave.is_file() and self.song_music is None:
self.song_music = audio.load_music_stream(self.tja.metadata.wave, 'song') self.song_music = audio.load_music_stream(self.tja.metadata.wave, 'song')
self.player_1 = PracticePlayer(self.tja, global_data.player_num, global_data.session_data[global_data.player_num-1].selected_difficulty, False, global_data.modifiers[0]) self.player_1 = PracticePlayer(self.tja, global_data.player_num, global_data.session_data[global_data.player_num-1].selected_difficulty, False, global_data.modifiers[0])
notes, branch_m, branch_e, branch_n = self.tja.notes_to_position(self.player_1.difficulty) notes, branch_m, branch_e, branch_n = self.tja.notes_to_position(self.player_1.difficulty)
_, self.scroll_note_list, self.bars = apply_modifiers(notes, self.player_1.modifiers) _, self.scrobble_note_list, self.bars = apply_modifiers(notes, self.player_1.modifiers)
self.start_ms = (get_current_ms() - self.tja.metadata.offset*1000) self.start_ms = (get_current_ms() - self.tja.metadata.offset*1000)
self.scrobble_index = 0 self.scrobble_index = 0
self.scrobble_time = self.bars[self.scrobble_index].hit_ms self.scrobble_time = self.bars[self.scrobble_index].hit_ms
@@ -62,15 +62,15 @@ class PracticeGameScreen(GameScreen):
resume_time = self.bars[resume_bar_index].hit_ms - first_bar_time + self.start_delay resume_time = self.bars[resume_bar_index].hit_ms - first_bar_time + self.start_delay
start_time = self.bars[previous_bar_index].hit_ms - first_bar_time start_time = self.bars[previous_bar_index].hit_ms - first_bar_time
tja_copy = copy.deepcopy(self.scrolling_tja) tja_copy = copy.deepcopy(self.scrobbling_tja)
self.player_1.tja = tja_copy self.player_1.tja = tja_copy
self.player_1.reset_chart() self.player_1.reset_chart()
self.player_1.don_notes = deque([note for note in self.player_1.don_notes if note.hit_ms >= resume_time]) self.player_1.don_notes = deque([note for note in self.player_1.don_notes if note.hit_ms > resume_time])
self.player_1.kat_notes = deque([note for note in self.player_1.kat_notes if note.hit_ms >= resume_time]) self.player_1.kat_notes = deque([note for note in self.player_1.kat_notes if note.hit_ms > resume_time])
self.player_1.other_notes = deque([note for note in self.player_1.other_notes if note.hit_ms >= resume_time]) self.player_1.other_notes = deque([note for note in self.player_1.other_notes if note.hit_ms > resume_time])
self.player_1.draw_note_list = deque([note for note in self.player_1.draw_note_list if note.hit_ms >= resume_time]) self.player_1.draw_note_list = deque([note for note in self.player_1.draw_note_list if note.hit_ms > resume_time])
self.player_1.draw_bar_list = deque([note for note in self.player_1.draw_bar_list if note.hit_ms >= resume_time]) self.player_1.draw_bar_list = deque([note for note in self.player_1.draw_bar_list if note.hit_ms > resume_time])
self.player_1.total_notes = len([note for note in self.player_1.play_notes if 0 < note.type < 5]) self.player_1.total_notes = len([note for note in self.player_1.play_notes if 0 < note.type < 5])
self.pause_time = start_time self.pause_time = start_time
@@ -80,10 +80,27 @@ class PracticeGameScreen(GameScreen):
self.start_ms = get_current_ms() - self.pause_time self.start_ms = get_current_ms() - self.pause_time
def global_keys(self): def global_keys(self):
super().global_keys() if ray.is_key_pressed(get_key_code(global_data.config["keys"]["restart_key"])):
if self.song_music is not None:
audio.stop_music_stream(self.song_music)
self.init_tja(global_data.session_data[global_data.player_num-1].selected_song)
audio.play_sound('restart', 'sound')
self.song_started = False
if ray.is_key_pressed(get_key_code(global_data.config["keys"]["back_key"])):
if self.song_music is not None:
audio.stop_music_stream(self.song_music)
return self.on_screen_end('PRACTICE_SELECT')
if ray.is_key_pressed(ray.KeyboardKey.KEY_SPACE):
self.pause_song()
if ray.is_key_pressed(ray.KeyboardKey.KEY_LEFT) or ray.is_key_pressed(ray.KeyboardKey.KEY_RIGHT): if ray.is_key_pressed(ray.KeyboardKey.KEY_LEFT) or ray.is_key_pressed(ray.KeyboardKey.KEY_RIGHT):
audio.play_sound('kat', 'sound') audio.play_sound('kat', 'sound')
if not self.scrobble_move.is_finished:
self.scrobble_time = self.bars[self.scrobble_index].hit_ms
old_index = self.scrobble_index old_index = self.scrobble_index
if ray.is_key_pressed(ray.KeyboardKey.KEY_LEFT): if ray.is_key_pressed(ray.KeyboardKey.KEY_LEFT):
self.scrobble_index = (self.scrobble_index - 1) if self.scrobble_index > 0 else len(self.bars) - 1 self.scrobble_index = (self.scrobble_index - 1) if self.scrobble_index > 0 else len(self.bars) - 1
@@ -96,12 +113,26 @@ class PracticeGameScreen(GameScreen):
self.scrobble_move.start() self.scrobble_move.start()
def update(self): def update(self):
super().update() super(GameScreen, self).update()
self.scrobble_move.update(get_current_ms()) current_time = get_current_ms()
self.transition.update(current_time)
if not self.paused:
self.current_ms = current_time - self.start_ms
self.start_song(current_time)
self.update_background(current_time)
if self.song_music is not None:
audio.update_music_stream(self.song_music)
self.scrobble_move.update(current_time)
if self.scrobble_move.is_finished: if self.scrobble_move.is_finished:
self.scrobble_time = self.bars[self.scrobble_index].hit_ms self.scrobble_time = self.bars[self.scrobble_index].hit_ms
self.scrobble_move.reset() self.scrobble_move.reset()
self.player_1.update(self.current_ms, current_time, self.background)
self.song_info.update(current_time)
return self.global_keys()
def get_position_x(self, width: int, current_ms: float, load_ms: float, pixels_per_frame: float) -> int: def get_position_x(self, width: int, current_ms: float, load_ms: float, pixels_per_frame: float) -> int:
"""Calculates the x-coordinate of a note based on its load time and current time""" """Calculates the x-coordinate of a note based on its load time and current time"""
if self.paused: if self.paused:
@@ -118,7 +149,7 @@ class PracticeGameScreen(GameScreen):
def draw_drumroll(self, current_ms: float, head: Drumroll, current_eighth: int, index: int): def draw_drumroll(self, current_ms: float, head: Drumroll, current_eighth: int, index: int):
"""Draws a drumroll in the player's lane""" """Draws a drumroll in the player's lane"""
start_position = self.get_position_x(SCREEN_WIDTH, current_ms, head.load_ms, head.pixels_per_frame_x) start_position = self.get_position_x(SCREEN_WIDTH, current_ms, head.load_ms, head.pixels_per_frame_x)
tail = self.scroll_note_list[index + 1] tail = next((note for note in self.scrobble_note_list if note.index == index+1), self.scrobble_note_list[index+1])
is_big = int(head.type == 6) is_big = int(head.type == 6)
end_position = self.get_position_x(SCREEN_WIDTH, current_ms, tail.load_ms, tail.pixels_per_frame_x) end_position = self.get_position_x(SCREEN_WIDTH, current_ms, tail.load_ms, tail.pixels_per_frame_x)
length = end_position - start_position length = end_position - start_position
@@ -140,7 +171,7 @@ class PracticeGameScreen(GameScreen):
"""Draws a balloon in the player's lane""" """Draws a balloon in the player's lane"""
offset = 12 offset = 12
start_position = self.get_position_x(SCREEN_WIDTH, current_ms, head.load_ms, head.pixels_per_frame_x) start_position = self.get_position_x(SCREEN_WIDTH, current_ms, head.load_ms, head.pixels_per_frame_x)
tail = self.scroll_note_list[index + 1] tail = next((note for note in self.scrobble_note_list if note.index == index+1), self.scrobble_note_list[index+1])
end_position = self.get_position_x(SCREEN_WIDTH, current_ms, tail.load_ms, tail.pixels_per_frame_x) end_position = self.get_position_x(SCREEN_WIDTH, current_ms, tail.load_ms, tail.pixels_per_frame_x)
pause_position = 349 pause_position = 349
if current_ms >= tail.hit_ms: if current_ms >= tail.hit_ms:
@@ -153,50 +184,54 @@ class PracticeGameScreen(GameScreen):
tex.draw_texture('notes', str(head.type), frame=current_eighth % 2, x=position-offset, y=192) tex.draw_texture('notes', str(head.type), frame=current_eighth % 2, x=position-offset, y=192)
tex.draw_texture('notes', '10', frame=current_eighth % 2, x=position-offset+128, y=192) tex.draw_texture('notes', '10', frame=current_eighth % 2, x=position-offset+128, y=192)
def draw(self): def draw_scrobble_list(self):
super().draw() bar_draws = []
if self.paused: for bar in reversed(self.bars):
# Batch bar draws by pre-calculating positions if not bar.display:
bar_draws = [] continue
for bar in reversed(self.bars): x_position = self.get_position_x(SCREEN_WIDTH, self.current_ms, bar.load_ms, bar.pixels_per_frame_x)
if not bar.display: y_position = self.get_position_y(self.current_ms, bar.load_ms, bar.pixels_per_frame_y, bar.pixels_per_frame_x)
continue if x_position < 236 or x_position > SCREEN_WIDTH:
x_position = self.get_position_x(SCREEN_WIDTH, self.current_ms, bar.load_ms, bar.pixels_per_frame_x) continue
y_position = self.get_position_y(self.current_ms, bar.load_ms, bar.pixels_per_frame_y, bar.pixels_per_frame_x) if hasattr(bar, 'is_branch_start'):
frame = 1
else:
frame = 0
bar_draws.append((str(bar.type), frame, x_position+60, y_position+190))
for bar_type, frame, x, y in bar_draws:
tex.draw_texture('notes', bar_type, frame=frame, x=x, y=y)
for note in reversed(self.scrobble_note_list):
if note.type == 8:
continue
if isinstance(note, Drumroll):
self.draw_drumroll(self.current_ms, note, 0, note.index)
elif isinstance(note, Balloon) and not note.is_kusudama:
x_position = self.get_position_x(SCREEN_WIDTH, self.current_ms, note.load_ms, note.pixels_per_frame_x)
y_position = self.get_position_y(self.current_ms, note.load_ms, note.pixels_per_frame_y, note.pixels_per_frame_x)
if x_position < 236 or x_position > SCREEN_WIDTH: if x_position < 236 or x_position > SCREEN_WIDTH:
continue continue
if hasattr(bar, 'is_branch_start'): self.draw_balloon(self.current_ms, note, 0, note.index)
frame = 1 tex.draw_texture('notes', 'moji', frame=note.moji, x=x_position - (168//2) + 64, y=323 + y_position)
else: else:
frame = 0 x_position = self.get_position_x(SCREEN_WIDTH, self.current_ms, note.load_ms, note.pixels_per_frame_x)
bar_draws.append((str(bar.type), frame, x_position+60, y_position+190)) y_position = self.get_position_y(self.current_ms, note.load_ms, note.pixels_per_frame_y, note.pixels_per_frame_x)
if x_position < 236 or x_position > SCREEN_WIDTH:
# Draw all bars in one batch
for bar_type, frame, x, y in bar_draws:
tex.draw_texture('notes', bar_type, frame=frame, x=x, y=y)
for note in reversed(self.scroll_note_list):
if note.type == 8:
continue continue
if isinstance(note, Drumroll): if note.display:
self.draw_drumroll(self.current_ms, note, 0, note.index) tex.draw_texture('notes', str(note.type), x=x_position, y=y_position+192, center=True)
elif isinstance(note, Balloon) and not note.is_kusudama: tex.draw_texture('notes', 'moji', frame=note.moji, x=x_position - (168//2) + 64, y=323 + y_position)
x_position = self.get_position_x(SCREEN_WIDTH, self.current_ms, note.load_ms, note.pixels_per_frame_x)
y_position = self.get_position_y(self.current_ms, note.load_ms, note.pixels_per_frame_y, note.pixels_per_frame_x)
if x_position < 236 or x_position > SCREEN_WIDTH:
continue
self.draw_balloon(self.current_ms, note, 0, note.index)
tex.draw_texture('notes', 'moji', frame=note.moji, x=x_position - (168//2) + 64, y=323 + y_position)
else:
x_position = self.get_position_x(SCREEN_WIDTH, self.current_ms, note.load_ms, note.pixels_per_frame_x)
y_position = self.get_position_y(self.current_ms, note.load_ms, note.pixels_per_frame_y, note.pixels_per_frame_x)
if x_position < 236 or x_position > SCREEN_WIDTH:
continue
if note.display: def draw(self):
tex.draw_texture('notes', str(note.type), x=x_position, y=y_position+192, center=True) self.background.draw()
tex.draw_texture('notes', 'moji', frame=note.moji, x=x_position - (168//2) + 64, y=323 + y_position) self.player_1.draw(self.current_ms, self.start_ms, self.mask_shader)
if self.paused:
self.draw_scrobble_list()
self.player_1.draw_overlays(self.mask_shader)
self.draw_overlay()
class PracticePlayer(Player): class PracticePlayer(Player):
@@ -206,7 +241,24 @@ class PracticePlayer(Player):
self.gauge = None self.gauge = None
self.paused = False self.paused = False
def draw_note_types(self, ms_from_start: float, start_ms: float): def draw(self, ms_from_start: float, start_ms: float, mask_shader: ray.Shader, dan_transition = None):
# Group 1: Background and lane elements
tex.draw_texture('lane', 'lane_background', index=self.is_2p)
if self.branch_indicator is not None:
self.branch_indicator.draw()
if self.gauge is not None:
self.gauge.draw()
if self.lane_hit_effect is not None:
self.lane_hit_effect.draw()
tex.draw_texture('lane', 'lane_hit_circle', index=self.is_2p)
# Group 2: Judgement and hit effects
if self.gogo_time is not None:
self.gogo_time.draw()
for anim in self.draw_judge_list:
anim.draw()
# Group 3: Notes and bars (game content)
if not self.paused: if not self.paused:
self.draw_bars(ms_from_start) self.draw_bars(ms_from_start)
self.draw_notes(ms_from_start, start_ms) self.draw_notes(ms_from_start, start_ms)