cleaning up

This commit is contained in:
Anthony Samms
2025-12-02 15:23:23 -05:00
parent d543a594af
commit f5896c7d63
6 changed files with 442 additions and 1322 deletions

View File

@@ -135,7 +135,7 @@ class GameScreen(Screen):
def init_tja(self, song: Path):
"""Initialize the TJA file"""
self.tja = TJAParser(song, start_delay=self.start_delay, distance=tex.screen_width - GameScreen.JUDGE_X)
self.tja = TJAParser(song, start_delay=self.start_delay)
if self.tja.metadata.bgmovie != Path() and self.tja.metadata.bgmovie.exists():
self.movie = VideoPlayer(self.tja.metadata.bgmovie)
self.movie.set_volume(0.0)
@@ -460,8 +460,8 @@ class Player:
self.draw_note_list.extend(branch_section.draw_notes)
self.draw_bar_list.extend(branch_section.bars)
self.play_notes = deque(sorted(self.play_notes))
self.draw_note_list = deque(sorted(self.draw_note_list, key=lambda x: x.load_ms))
self.draw_bar_list = deque(sorted(self.draw_bar_list, key=lambda x: x.load_ms))
self.draw_note_list = deque(sorted(self.draw_note_list, key=lambda x: x.hit_ms))
self.draw_bar_list = deque(sorted(self.draw_bar_list, key=lambda x: x.hit_ms))
total_don = [note for note in self.play_notes if note.type in {NoteType.DON, NoteType.DON_L}]
total_kat = [note for note in self.play_notes if note.type in {NoteType.KAT, NoteType.KAT_L}]
total_other = [note for note in self.play_notes if note.type not in {NoteType.DON, NoteType.DON_L, NoteType.KAT, NoteType.KAT_L}]
@@ -474,24 +474,16 @@ class Player:
"""Returns the score, good count, ok count, bad count, max combo, and total drumroll"""
return self.score, self.good_count, self.ok_count, self.bad_count, self.max_combo, self.total_drumroll
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"""
# Override if delay active
if self.delay_start:
current_ms = self.delay_start
time_diff = load_ms - current_ms
return int(width + pixels_per_frame * 0.06 * time_diff - (tex.textures["notes"]["1"].width//2)) - self.visual_offset
def get_position_x(self, note, current_ms):
speedx = note.bpm / 240000 * note.scroll_x * (tex.screen_width - GameScreen.JUDGE_X) * tex.screen_scale
return GameScreen.JUDGE_X + (note.hit_ms - current_ms) * speedx
def get_position_y(self, current_ms: float, load_ms: float, pixels_per_frame: float, pixels_per_frame_x) -> int:
"""Calculates the y-coordinate of a note based on its load time and current time"""
# Override if delay active
if self.delay_start:
current_ms = self.delay_start
time_diff = load_ms - current_ms
if pixels_per_frame_x == 0:
return int(pixels_per_frame * 0.06 * time_diff)
return int((pixels_per_frame * 0.06 * time_diff) + ((self.tja.distance * pixels_per_frame) / pixels_per_frame_x))
def get_position_y(self, note, current_ms):
speedy = note.bpm / 240000 * note.scroll_y * (tex.screen_width - GameScreen.JUDGE_Y) * tex.screen_scale
return (note.hit_ms - current_ms) * speedy
'''
def handle_tjap3_extended_commands(self, current_ms: float):
if not self.timeline or self.timeline_index >= len(self.timeline):
return
@@ -531,6 +523,7 @@ class Player:
if should_advance:
self.timeline_index += 1
'''
def get_judge_position(self, current_ms: float):
"""Get the current judgment circle position based on bar data with on-demand interpolation"""
@@ -539,7 +532,7 @@ class Player:
timeline_object = self.timeline[self.timeline_index]
if hasattr(timeline_object, 'delta_x'):
if hasattr(timeline_object, 'judge_pos_x'):
if timeline_object.load_ms <= current_ms <= timeline_object.hit_ms:
duration = timeline_object.hit_ms - timeline_object.load_ms
if duration > 0:
@@ -567,6 +560,7 @@ class Player:
timeline_object = self.timeline[self.timeline_index]
should_advance = False
'''
if hasattr(timeline_object, 'bpmchange') and timeline_object.hit_ms <= current_ms:
hit_ms = timeline_object.hit_ms
bpmchange = timeline_object.bpmchange
@@ -584,6 +578,7 @@ class Player:
note.pixels_per_frame_y *= bpmchange
self.bpm *= bpmchange
should_advance = True
'''
if hasattr(timeline_object, 'delay') and timeline_object.hit_ms <= current_ms:
hit_ms = timeline_object.hit_ms
@@ -624,7 +619,7 @@ class Player:
"""Manages the bars and removes if necessary
Also sets branch conditions"""
#Add bar to current_bars list if it is ready to be shown on screen
if self.draw_bar_list and current_ms > self.draw_bar_list[0].load_ms:
if self.draw_bar_list and current_ms >= self.draw_bar_list[0].hit_ms - 10000:
self.current_bars.append(self.draw_bar_list.popleft())
#If a bar is off screen, remove it
@@ -632,10 +627,10 @@ class Player:
return
# More efficient removal with early exit
removal_threshold = GameScreen.JUDGE_X + (650 * tex.screen_scale)
removal_threshold = GameScreen.JUDGE_X - (650 * tex.screen_scale)
bars_to_keep = []
for bar in self.current_bars:
position = self.get_position_x(tex.screen_width, current_ms, bar.hit_ms, bar.pixels_per_frame_x)
position = self.get_position_x(bar, current_ms)
if position >= removal_threshold:
bars_to_keep.append(bar)
self.current_bars = bars_to_keep
@@ -647,6 +642,7 @@ class Player:
logger.info(f'branch condition measures started with conditions {self.branch_condition}, {e_req}, {m_req}, {self.current_bars[-1].hit_ms}')
if not self.is_branch:
self.is_branch = True
'''
if self.branch_condition == 'r':
end_time = self.branch_m[0].bars[0].load_ms
end_roll = -1
@@ -686,6 +682,7 @@ class Player:
seen_notes.add(note)
self.curr_branch_reqs = [e_req, m_req, branch_start_time, max(len(seen_notes), 1)]
'''
def play_note_manager(self, current_ms: float, background: Optional[Background]):
"""Manages the play_notes and removes if necessary"""
if self.don_notes and self.don_notes[0].hit_ms + Player.TIMING_BAD < current_ms:
@@ -745,7 +742,7 @@ class Player:
def draw_note_manager(self, current_ms: float):
"""Manages the draw_notes and removes if necessary"""
if self.draw_note_list and current_ms + 1000 >= self.draw_note_list[0].load_ms:
if self.draw_note_list and current_ms >= self.draw_note_list[0].hit_ms - 10000:
current_note = self.draw_note_list.popleft()
if 5 <= current_note.type <= 7:
bisect.insort_left(self.current_notes_draw, current_note, key=lambda x: x.index)
@@ -767,16 +764,14 @@ class Player:
note = self.current_notes_draw[0]
if note.type in {NoteType.ROLL_HEAD, NoteType.ROLL_HEAD_L, NoteType.BALLOON_HEAD, NoteType.KUSUDAMA} and len(self.current_notes_draw) > 1:
note = self.current_notes_draw[1]
if current_ms > note.hit_ms + 200:
if note.type == NoteType.TAIL:
self.current_notes_draw.pop(0)
if self.get_position_x(note, current_ms) < GameScreen.JUDGE_X:
self.current_notes_draw.pop(0)
def note_manager(self, current_ms: float, background: Optional[Background]):
self.bar_manager(current_ms)
self.play_note_manager(current_ms, background)
self.draw_note_manager(current_ms)
self.handle_tjap3_extended_commands(current_ms)
#self.handle_tjap3_extended_commands(current_ms)
def note_correct(self, note: Note, current_time: float):
"""Removes a note from the appropriate separated list"""
@@ -880,8 +875,8 @@ class Player:
if self.is_drumroll:
self.check_drumroll(drum_type, background, current_time)
elif self.is_balloon:
#if not isinstance(curr_note, Balloon):
#raise Exception("Balloon mode entered but current note is not balloon")
if not isinstance(curr_note, Balloon):
raise Exception("Balloon mode entered but current note is not balloon")
self.check_balloon(drum_type, curr_note, current_time)
else:
self.curr_drumroll_count = 0
@@ -1082,8 +1077,8 @@ class Player:
self.lane_hit_effect.update(current_time)
self.animation_manager(self.draw_drum_hit_list, current_time)
self.get_judge_position(ms_from_start)
self.handle_tjap3_extended_commands(ms_from_start)
self.handle_scroll_type_commands(ms_from_start)
'''
if self.delay_start is not None and self.delay_end is not None:
# Currently, a delay is active: notes should be frozen at ms = delay_start
# Check if it ended
@@ -1093,6 +1088,7 @@ class Player:
note.load_ms += delay
self.delay_start = None
self.delay_end = None
'''
self.update_bpm(ms_from_start)
# More efficient arc management
@@ -1123,30 +1119,6 @@ class Player:
if self.is_branch:
self.evaluate_branch(ms_from_start)
# Get the next note from any of the three lists for BPM and gogo time updates
'''
next_note = None
candidates = []
if self.don_notes:
candidates.append(self.don_notes[0])
if self.kat_notes:
candidates.append(self.kat_notes[0])
if self.other_notes:
candidates.append(self.other_notes[0])
if candidates:
next_note = min(candidates, key=lambda note: note.load_ms)
if next_note:
if next_note.gogo_time and not self.is_gogo_time:
self.is_gogo_time = True
self.gogo_time = GogoTime(self.is_2p)
self.chara.set_animation('gogo_start')
if not next_note.gogo_time and self.is_gogo_time:
self.is_gogo_time = False
self.gogo_time = None
self.chara.set_animation('gogo_stop')
'''
if self.gauge is None:
self.chara.update(current_time, self.bpm, False, False)
else:
@@ -1154,25 +1126,22 @@ class Player:
def draw_drumroll(self, current_ms: float, head: Drumroll, current_eighth: int):
"""Draws a drumroll in the player's lane"""
start_position = self.get_position_x(tex.screen_width, current_ms, head.load_ms, head.pixels_per_frame_x)
start_position += self.judge_x
start_position = self.get_position_x(head, current_ms)
tail = next((note for note in self.current_notes_draw[1:] if note.type == NoteType.TAIL and note.index > head.index), self.current_notes_draw[1])
is_big = int(head.type == NoteType.ROLL_HEAD_L)
end_position = self.get_position_x(tex.screen_width, current_ms, tail.load_ms, tail.pixels_per_frame_x)
end_position += self.judge_x
end_position = self.get_position_x(tail, current_ms)
length = end_position - start_position
color = ray.Color(255, head.color, head.color, 255)
y = tex.skin_config["notes"].y + self.get_position_y(current_ms, head.load_ms, head.pixels_per_frame_y, head.pixels_per_frame_x)
y = tex.skin_config["notes"].y + self.get_position_y(head, current_ms)
moji_y = tex.skin_config["moji"].y
moji_x = -(tex.textures["notes"]["moji"].width//2) + (tex.textures["notes"]["1"].width//2)
if head.display:
if length > 0:
tex.draw_texture('notes', "8", frame=is_big, x=start_position+(tex.textures["notes"]["5"].width//2), y=y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y, x2=length+tex.skin_config["drumroll_width_offset"].width, color=color)
if is_big:
tex.draw_texture('notes', "drumroll_big_tail", x=end_position+tex.textures["notes"]["5"].width//2, y=y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y, color=color)
else:
tex.draw_texture('notes', "drumroll_tail", x=end_position+tex.textures["notes"]["5"].width//2, y=y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y, color=color)
tex.draw_texture('notes', str(head.type), frame=current_eighth % 2, x=start_position, y=y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y, color=color)
tex.draw_texture('notes', "8", frame=is_big, x=start_position, y=y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y, x2=length+tex.skin_config["drumroll_width_offset"].width, color=color)
if is_big:
tex.draw_texture('notes', "drumroll_big_tail", x=end_position, y=y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y, color=color)
else:
tex.draw_texture('notes', "drumroll_tail", x=end_position, y=y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y, color=color)
tex.draw_texture('notes', str(head.type), frame=current_eighth % 2, x=start_position - tex.textures["notes"]["1"].width//2, y=y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y, color=color)
tex.draw_texture('notes', 'moji_drumroll_mid', x=start_position + tex.textures["notes"]["1"].width//2, y=moji_y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y, x2=length)
tex.draw_texture('notes', 'moji', frame=head.moji, x=start_position + moji_x, y=moji_y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y)
@@ -1181,13 +1150,11 @@ class Player:
def draw_balloon(self, current_ms: float, head: Balloon, current_eighth: int):
"""Draws a balloon in the player's lane"""
offset = tex.skin_config["balloon_offset"].x
start_position = self.get_position_x(tex.screen_width, current_ms, head.load_ms, head.pixels_per_frame_x)
start_position += self.judge_x
start_position = self.get_position_x(head, current_ms)
tail = next((note for note in self.current_notes_draw[1:] if note.type == NoteType.TAIL and note.index > head.index), self.current_notes_draw[1])
end_position = self.get_position_x(tex.screen_width, current_ms, tail.load_ms, tail.pixels_per_frame_x)
end_position += self.judge_x
pause_position = tex.skin_config["balloon_pause_position"].x + self.judge_x
y = tex.skin_config["notes"].y + self.get_position_y(current_ms, head.load_ms, head.pixels_per_frame_y, head.pixels_per_frame_x)
end_position = self.get_position_x(tail, current_ms)
pause_position = GameScreen.JUDGE_X
y = tex.skin_config["notes"].y + self.get_position_y(head, current_ms)
if current_ms >= tail.hit_ms:
position = end_position
elif current_ms >= head.hit_ms:
@@ -1195,8 +1162,8 @@ class Player:
else:
position = start_position
if head.display:
tex.draw_texture('notes', str(head.type), frame=current_eighth % 2, x=position-offset, y=y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y)
tex.draw_texture('notes', '10', frame=current_eighth % 2, x=position-offset+tex.textures["notes"]["10"].width, y=y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y)
tex.draw_texture('notes', str(head.type), frame=current_eighth % 2, x=position-offset - tex.textures["notes"]["1"].width//2, y=y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y)
tex.draw_texture('notes', '10', frame=current_eighth % 2, x=position-offset+tex.textures["notes"]["10"].width - tex.textures["notes"]["1"].width//2, y=y+(self.is_2p*tex.skin_config["2p_offset"].y)+self.judge_y)
def draw_bars(self, current_ms: float):
"""Draw bars in the player's lane"""
@@ -1206,29 +1173,19 @@ class Player:
for bar in reversed(self.current_bars):
if not bar.display:
continue
x_position = self.get_position_x(tex.screen_width, current_ms, bar.load_ms, bar.pixels_per_frame_x)
y_position = self.get_position_y(current_ms, bar.load_ms, bar.pixels_per_frame_y, bar.pixels_per_frame_x)
x_position += self.judge_x
y_position += self.judge_y
if hasattr(bar, 'is_branch_start'):
frame = 1
else:
frame = 0
x_position = self.get_position_x(bar, current_ms)
y_position = self.get_position_y(bar, current_ms)
if y_position != 0:
angle = math.degrees(math.atan2(bar.pixels_per_frame_y, bar.pixels_per_frame_x))
angle = math.degrees(math.atan2(bar.scroll_y, bar.scroll_x))
else:
angle = 0
tex.draw_texture('notes', str(bar.type), frame=frame, x=x_position+tex.skin_config["moji_drumroll"].x, y=y_position+tex.skin_config["moji_drumroll"].y+(self.is_2p*tex.skin_config["2p_offset"].y), rotation=angle)
tex.draw_texture('notes', str(bar.type), x=x_position+tex.skin_config["moji_drumroll"].x- (tex.textures["notes"]["1"].width//2), y=y_position+tex.skin_config["moji_drumroll"].y+(self.is_2p*tex.skin_config["2p_offset"].y), rotation=angle)
def draw_notes(self, current_ms: float, start_ms: float):
def draw_notes(self, current_ms: float):
"""Draw notes in the player's lane"""
if not self.current_notes_draw:
return
eighth_in_ms = 0 if self.bpm == 0 else (60000 * 4 / self.bpm) / 8
current_eighth = 0
if self.combo >= 50 and eighth_in_ms != 0:
current_eighth = int((current_ms - start_ms) // eighth_in_ms)
for note in reversed(self.current_notes_draw):
if self.balloon_anim is not None and note == self.current_notes_draw[0]:
@@ -1236,6 +1193,7 @@ class Player:
if note.type == NoteType.TAIL:
continue
current_eighth = 0
if hasattr(note, 'sudden_appear_ms') and hasattr(note, 'sudden_moving_ms'):
appear_ms = note.hit_ms - note.sudden_appear_ms
moving_start_ms = note.hit_ms - note.sudden_moving_ms
@@ -1247,14 +1205,11 @@ class Player:
effective_ms = moving_start_ms
else:
effective_ms = current_ms
x_position = self.get_position_x(tex.screen_width, effective_ms, note.load_ms, note.pixels_per_frame_x)
y_position = self.get_position_y(effective_ms, note.load_ms, note.pixels_per_frame_y, note.pixels_per_frame_x)
x_position = self.get_position_x(note, effective_ms)
y_position = self.get_position_y(note, effective_ms)
else:
x_position = self.get_position_x(tex.screen_width, current_ms, note.load_ms, note.pixels_per_frame_x)
y_position = self.get_position_y(current_ms, note.load_ms, note.pixels_per_frame_y, note.pixels_per_frame_x)
x_position += self.judge_x
y_position += self.judge_y
x_position = self.get_position_x(note, current_ms)
y_position = self.get_position_y(note, current_ms)
if isinstance(note, Drumroll):
self.draw_drumroll(current_ms, note, current_eighth)
elif isinstance(note, Balloon) and not note.is_kusudama:
@@ -1262,10 +1217,8 @@ class Player:
tex.draw_texture('notes', 'moji', frame=note.moji, x=x_position, y=tex.skin_config["moji"].y + y_position+(self.is_2p*tex.skin_config["2p_offset"].y))
else:
if note.display:
tex.draw_texture('notes', str(note.type), frame=current_eighth % 2, x=x_position, y=y_position+tex.skin_config["notes"].y+(self.is_2p*tex.skin_config["2p_offset"].y), center=True)
tex.draw_texture('notes', 'moji', frame=note.moji, x=x_position - (tex.textures["notes"]["moji"].width//2) + (tex.textures["notes"]["1"].width//2), y=tex.skin_config["moji"].y + y_position+(self.is_2p*tex.skin_config["2p_offset"].y))
ray.draw_text(self.current_notes_draw[0].lyric, tex.screen_width//2 - (ray.measure_text(self.current_notes_draw[0].lyric, int(40 * tex.screen_scale))//2), tex.screen_height - int(50 * tex.screen_scale), int(40 * tex.screen_scale), ray.BLUE)
tex.draw_texture('notes', str(note.type), frame=current_eighth % 2, x=x_position - (tex.textures["notes"]["1"].width//2), y=y_position+tex.skin_config["notes"].y+(self.is_2p*tex.skin_config["2p_offset"].y), center=True)
tex.draw_texture('notes', 'moji', frame=note.moji, x=x_position - (tex.textures["notes"]["moji"].width//2), y=tex.skin_config["moji"].y + y_position+(self.is_2p*tex.skin_config["2p_offset"].y))
def draw_modifiers(self):
@@ -1367,7 +1320,7 @@ class Player:
# Group 3: Notes and bars (game content)
self.draw_bars(ms_from_start)
self.draw_notes(ms_from_start, start_ms)
self.draw_notes(ms_from_start)
if dan_transition is not None:
dan_transition.draw()