From de74d022456392231b19bef2e05f091bc9ece017 Mon Sep 17 00:00:00 2001 From: Yonokid <37304577+Yonokid@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:35:46 -0400 Subject: [PATCH] a little bit of refactoring methinks --- game.py | 348 +++++++++++++++++++++++++----------------------- global_funcs.py | 171 +++++++++++++----------- title.py | 86 ++++++------ 3 files changed, 312 insertions(+), 293 deletions(-) diff --git a/game.py b/game.py index d078d5d..ba7d080 100644 --- a/game.py +++ b/game.py @@ -25,32 +25,32 @@ class GameScreen: self.texture_score_cover = load_texture_from_zip(zip_file, 'lane_obi_img00003.png') self.texture_don = [load_texture_from_zip(zip_file, 'onp_don_img00000.png'), - load_texture_from_zip(zip_file, 'onp_don_img00001.png')] + load_texture_from_zip(zip_file, 'onp_don_img00001.png')] self.texture_kat = [load_texture_from_zip(zip_file, 'onp_katsu_img00000.png'), - load_texture_from_zip(zip_file, 'onp_katsu_img00001.png')] + load_texture_from_zip(zip_file, 'onp_katsu_img00001.png')] self.texture_dai_don = [load_texture_from_zip(zip_file, 'onp_don_dai_img00000.png'), - load_texture_from_zip(zip_file, 'onp_don_dai_img00001.png')] + load_texture_from_zip(zip_file, 'onp_don_dai_img00001.png')] self.texture_dai_kat = [load_texture_from_zip(zip_file, 'onp_katsu_dai_img00000.png'), - load_texture_from_zip(zip_file, 'onp_katsu_dai_img00001.png')] + load_texture_from_zip(zip_file, 'onp_katsu_dai_img00001.png')] self.texture_balloon_head = [load_texture_from_zip(zip_file, 'onp_fusen_img00001.png'), - load_texture_from_zip(zip_file, 'onp_fusen_img00002.png')] + load_texture_from_zip(zip_file, 'onp_fusen_img00002.png')] self.texture_balloon_tail = [load_texture_from_zip(zip_file, 'onp_fusen_img00000.png'), - load_texture_from_zip(zip_file, 'onp_fusen_img00000.png')] + load_texture_from_zip(zip_file, 'onp_fusen_img00000.png')] self.texture_drumroll_head = [load_texture_from_zip(zip_file, 'onp_renda_img00002.png'), - load_texture_from_zip(zip_file, 'onp_renda_img00003.png')] + load_texture_from_zip(zip_file, 'onp_renda_img00003.png')] self.texture_drumroll_body = [load_texture_from_zip(zip_file, 'onp_renda_img00000.png'), - load_texture_from_zip(zip_file, 'onp_renda_img00000.png')] + load_texture_from_zip(zip_file, 'onp_renda_img00000.png')] self.texture_drumroll_tail = [load_texture_from_zip(zip_file, 'onp_renda_img00001.png'), - load_texture_from_zip(zip_file, 'onp_renda_img00001.png')] + load_texture_from_zip(zip_file, 'onp_renda_img00001.png')] self.texture_dai_drumroll_head = [load_texture_from_zip(zip_file, 'onp_renda_dai_img00002.png'), - load_texture_from_zip(zip_file, 'onp_renda_dai_img00003.png')] + load_texture_from_zip(zip_file, 'onp_renda_dai_img00003.png')] self.texture_dai_drumroll_body = [load_texture_from_zip(zip_file, 'onp_renda_dai_img00000.png'), - load_texture_from_zip(zip_file, 'onp_renda_dai_img00000.png')] + load_texture_from_zip(zip_file, 'onp_renda_dai_img00000.png')] self.texture_dai_drumroll_tail = [load_texture_from_zip(zip_file, 'onp_renda_dai_img00001.png'), - load_texture_from_zip(zip_file, 'onp_renda_dai_img00001.png')] + load_texture_from_zip(zip_file, 'onp_renda_dai_img00001.png')] self.texture_drumroll_count = load_texture_from_zip(zip_file, 'renda_num_img00000.png') self.texture_drumroll_number = [] for i in range(1, 11): @@ -183,6 +183,7 @@ class GameScreen: 'dai_drumroll_body': self.texture_dai_drumroll_body, 'dai_drumroll_tail': self.texture_dai_drumroll_tail, 'balloon_tail': self.texture_balloon_tail} + self.tja = TJAParser(f'Songs\\{song}') self.tja.get_metadata() self.tja.distance = self.width - self.judge_x @@ -210,7 +211,7 @@ class Player: self.difficulty = difficulty self.play_note_list, self.draw_note_list, self.draw_bar_list = game_screen.tja.notes_to_position(self.difficulty) - self.base_score = self.calculate_base_score() + self.base_score = calculate_base_score(self.play_note_list) self.judge_offset = 0 @@ -247,49 +248,64 @@ class Player: self.score_list = [] self.base_score_list = [] - def calculate_base_score(self): - total_notes = 0 - balloon_num = 0 - balloon_sec = 0 - balloon_count = 0 - drumroll_sec = 0 - for i in range(len(self.play_note_list)): - note = self.play_note_list[i] - if i < len(self.play_note_list)-1: - next_note = self.play_note_list[i+1] - else: - next_note = self.play_note_list[len(self.play_note_list)-1] - if note.get('note') in {'1','2','3','4'}: - total_notes += 1 - elif note.get('note') in {'5', '6'}: - drumroll_sec += (next_note.get('ms') - note.get('ms')) / 1000 - elif note.get('note') in {'7', '9'}: - balloon_num += 1 - balloon_count += next_note.get('balloon') - total_score = (1000000 - (balloon_count * 100) - (drumroll_sec * 1692.0079999994086)) / total_notes - return math.ceil(total_score / 10) * 10 - def get_position(self, game_screen, ms, pixels_per_frame): return int(game_screen.width + pixels_per_frame * 60 / 1000 * (ms - game_screen.current_ms + self.judge_offset) - 64) def animation_manager(self, game_screen, animation_list): - if len(animation_list) != 0: - for i in range(len(animation_list)-1, -1, -1): - animation = animation_list[i] - animation.update(game_screen.current_ms) - if animation.is_finished: - animation_list.pop(i) + if len(animation_list) <= 0: + return + for i in range(len(animation_list)-1, -1, -1): + animation = animation_list[i] + animation.update(game_screen.current_ms) + if animation.is_finished: + animation_list.pop(i) - def note_manager(self, game_screen): + def bar_manager(self, game_screen): #Add bar to current_bars list if it is ready to be shown on screen if len(self.draw_bar_list) > 0 and game_screen.current_ms > self.draw_bar_list[0]['load_ms']: self.current_bars.append(self.draw_bar_list.popleft()) + #If a bar is off screen, remove it + if len(self.current_bars) <= 0: + return + + for i in range(len(self.current_bars)-1, -1, -1): + bar_ms, pixels_per_frame = self.current_bars[i]['ms'], self.current_bars[i]['ppf'] + position = self.get_position(game_screen, bar_ms, pixels_per_frame) + if position < game_screen.judge_x + 650: + self.current_bars.pop(i) + + def play_note_manager(self, game_screen): #Add note to current_notes list if it is ready to be shown on screen if len(self.play_note_list) > 0 and game_screen.current_ms + 1000 >= self.play_note_list[0]['load_ms']: self.current_notes.append(self.play_note_list.popleft()) if len(self.play_note_list) > 0 and self.play_note_list[0]['note'] == '8': self.current_notes.append(self.play_note_list.popleft()) + + #if a note was not hit within the window, remove it + if len(self.current_notes) == 0: + return + + note = self.current_notes[0] + if note['ms'] + self.timing_bad < game_screen.current_ms: + if note['note'] in {'1', '2', '3', '4'}: + self.combo = 0 + self.bad_count += 1 + self.current_notes.popleft() + elif (note['ms'] <= game_screen.current_ms): + if note['note'] == '5': + self.is_drumroll = True + self.drumroll_big = 0 + elif note['note'] == '6': + self.is_drumroll = True + self.drumroll_big = 2 + elif note['note'] == '7': + self.is_balloon = True + elif note['note'] == '8' and (self.is_drumroll or self.is_balloon): + self.is_drumroll = False + self.is_balloon = False + + def draw_note_manager(self, game_screen): if len(self.draw_note_list) > 0 and game_screen.current_ms + 1000 >= self.draw_note_list[0]['load_ms']: if self.draw_note_list[0]['note'] in {'5','6','7','9'}: while self.draw_note_list[0]['note'] != '8': @@ -298,49 +314,26 @@ class Player: else: self.current_notes_draw.append(self.draw_note_list.popleft()) - #if a note was not hit within the window, remove it - if len(self.current_notes) != 0: - note = self.current_notes[0] - if note['ms'] + self.timing_bad < game_screen.current_ms: - if note['note'] in {'1', '2', '3', '4'}: - self.combo = 0 - self.bad_count += 1 - self.current_notes.popleft() - elif (note['ms'] <= game_screen.current_ms): - if note['note'] == '5': - self.is_drumroll = True - self.drumroll_big = 0 - elif note['note'] == '6': - self.is_drumroll = True - self.drumroll_big = 2 - elif note['note'] == '7': - self.is_balloon = True - elif note['note'] == '8' and (self.is_drumroll or self.is_balloon): - self.is_drumroll = False - self.is_balloon = False - #If a bar is off screen, remove it - if len(self.current_bars) != 0: - for i in range(len(self.current_bars)-1, -1, -1): - bar_ms, pixels_per_frame = self.current_bars[i]['ms'], self.current_bars[i]['ppf'] - position = self.get_position(game_screen, bar_ms, pixels_per_frame) - if position < game_screen.judge_x + 650: - self.current_bars.pop(i) - #If a note is off screen, remove it - if len(self.current_notes_draw) != 0: - for i in range(len(self.current_notes_draw)-1, -1, -1): - note_type, note_ms, pixels_per_frame = self.current_notes_draw[i]['note'], self.current_notes_draw[i]['ms'], self.current_notes_draw[i]['ppf'] - position = self.get_position(game_screen, note_ms, pixels_per_frame) - if position < game_screen.judge_x + 650 and note_type not in {'5', '6', '7'}: - if note_type == '8' and self.current_notes_draw[i-1]['note'] in {'5', '6', '7'} and self.current_notes_draw[i-1]['ms'] < self.current_notes_draw[i]['ms']: - self.current_notes_draw.pop(i-1) - else: - self.current_notes_draw.pop(i) + if len(self.current_notes_draw) == 0: + return - if len(self.current_notes_draw) != 0: - if self.current_notes_draw[0]['note'] in {'5', '6', '8'}: - if 255 > self.current_notes_draw[0]['color'] > 0: - self.current_notes_draw[0]['color'] += 1 + if self.current_notes_draw[0]['note'] in {'5', '6', '8'} and 255 > self.current_notes_draw[0]['color'] > 0: + self.current_notes_draw[0]['color'] += 1 + + for i in range(len(self.current_notes_draw)-1, -1, -1): + note_type, note_ms, pixels_per_frame = self.current_notes_draw[i]['note'], self.current_notes_draw[i]['ms'], self.current_notes_draw[i]['ppf'] + position = self.get_position(game_screen, note_ms, pixels_per_frame) + if position < game_screen.judge_x + 650 and note_type not in {'5', '6', '7'}: + if note_type == '8' and self.current_notes_draw[i-1]['note'] in {'5', '6', '7'} and self.current_notes_draw[i-1]['ms'] < self.current_notes_draw[i]['ms']: + self.current_notes_draw.pop(i-1) + else: + self.current_notes_draw.pop(i) + + def note_manager(self, game_screen): + self.bar_manager(game_screen) + self.play_note_manager(game_screen) + self.draw_note_manager(game_screen) def note_correct(self, game_screen, note): index = note['index'] @@ -365,33 +358,39 @@ class Player: else: self.current_notes_draw.pop(i) + def check_drumroll(self, game_screen, drum_type): + note_type = game_screen.note_type_dict[str(int(drum_type)+self.drumroll_big)] + self.draw_arc_list.append(NoteArc(note_type, game_screen.current_ms, self.player_number)) + self.curr_drumroll_count += 1 + self.score += 100 + self.base_score_list.append(ScoreCounterAnimation(game_screen.current_ms, 100)) + color = 255 - (self.curr_drumroll_count*10) + if color < 0: + self.current_notes_draw[0]['color'] = 0 + else: + self.current_notes_draw[0]['color'] = color + + def check_balloon(self, game_screen, drum_type): + current_note = self.current_notes[0] + if current_note['note'] == '7': + current_note = self.current_notes[1] + if len(self.balloon_list) < 1: + self.balloon_list.append(BalloonAnimation(game_screen.current_ms, current_note['balloon'])) + self.curr_balloon_count += 1 + self.score += 100 + self.base_score_list.append(ScoreCounterAnimation(game_screen.current_ms, 100)) + self.current_notes_draw[0]['popped'] = False + if self.curr_balloon_count == current_note['balloon']: + self.is_balloon = False + self.current_notes_draw[0]['popped'] = True + ray.play_sound(game_screen.sound_balloon_pop) + self.note_correct(game_screen, self.current_notes[0]) + def check_note(self, game_screen, drum_type): if self.is_drumroll: - note_type = game_screen.note_type_dict[str(int(drum_type)+self.drumroll_big)] - self.draw_arc_list.append(NoteArc(note_type, game_screen.current_ms, self.player_number)) - self.curr_drumroll_count += 1 - self.score += 100 - self.base_score_list.append(ScoreCounterAnimation(game_screen.current_ms, 100)) - color = 255 - (self.curr_drumroll_count*10) - if color < 0: - self.current_notes_draw[0]['color'] = 0 - else: - self.current_notes_draw[0]['color'] = color + self.check_drumroll(game_screen, drum_type) elif self.is_balloon and drum_type == '1': - current_note = self.current_notes[0] - if current_note['note'] == '7': - current_note = self.current_notes[1] - if len(self.balloon_list) < 1: - self.balloon_list.append(BalloonAnimation(game_screen.current_ms, current_note['balloon'])) - self.curr_balloon_count += 1 - self.score += 100 - self.base_score_list.append(ScoreCounterAnimation(game_screen.current_ms, 100)) - self.current_notes_draw[0]['popped'] = False - if self.curr_balloon_count == current_note['balloon']: - self.is_balloon = False - self.current_notes_draw[0]['popped'] = True - ray.play_sound(game_screen.sound_balloon_pop) - self.note_correct(game_screen, self.current_notes[0]) + self.check_balloon(game_screen, drum_type) elif len(self.current_notes) != 0: self.curr_drumroll_count = 0 self.curr_balloon_count = 0 @@ -444,21 +443,25 @@ class Player: if len(self.drumroll_counter) == 0 or self.drumroll_counter[-1].is_finished: self.drumroll_counter.append(DrumrollCounter(game_screen.current_ms)) - if len(self.drumroll_counter) > 0: - if self.drumroll_counter[0].is_finished and not self.is_drumroll: - self.drumroll_counter.pop(0) - else: - self.drumroll_counter[0].update(game_screen, game_screen.current_ms, self.curr_drumroll_count) + if len(self.drumroll_counter) <= 0: + return + + if self.drumroll_counter[0].is_finished and not self.is_drumroll: + self.drumroll_counter.pop(0) + else: + self.drumroll_counter[0].update(game_screen, game_screen.current_ms, self.curr_drumroll_count) def balloon_animation_manager(self, game_screen): - if len(self.balloon_list) != 0: - if self.balloon_list[0].is_finished: - self.balloon_list.pop(0) + if len(self.balloon_list) <= 0: + return + + if self.balloon_list[0].is_finished: + self.balloon_list.pop(0) + else: + if self.is_balloon: + self.balloon_list[0].update(game_screen, game_screen.current_ms, self.curr_balloon_count, False) else: - if self.is_balloon: - self.balloon_list[0].update(game_screen, game_screen.current_ms, self.curr_balloon_count, False) - else: - self.balloon_list[0].update(game_screen, game_screen.current_ms, self.curr_balloon_count, True) + self.balloon_list[0].update(game_screen, game_screen.current_ms, self.curr_balloon_count, True) def combo_manager(self, game_screen): if self.combo >= 3 and len(self.combo_list) == 0: @@ -497,6 +500,7 @@ class Player: self.check_note(game_screen, '2') def update(self, game_screen): + #pls help turn this into priority queue instead of sorting every frame thanks self.current_notes_draw = sorted(self.current_notes_draw, key=lambda d: d['ms']) self.note_manager(game_screen) self.combo_manager(game_screen) @@ -554,61 +558,65 @@ class Player: y = 184 ray.draw_texture(game_screen.texture_barline, position+note_padding-4, y+6, ray.WHITE) return - elif note in game_screen.note_type_dict: - eighth_in_ms = (60000 * 4 / game_screen.tja.bpm) / 8 - if self.combo >= 50: - current_eighth = int((game_screen.current_ms - game_screen.start_ms) // eighth_in_ms) - else: - current_eighth = 0 - if note in {'5', '6', 'drumroll_tail', 'dai_drumroll_tail', 'drumroll_body', 'dai_drumroll_body'}: - draw_color = color - else: - draw_color = 255 - if note == '7': - offset = 12 - balloon = True - else: + elif note not in game_screen.note_type_dict: + return + + eighth_in_ms = (60000 * 4 / game_screen.tja.bpm) / 8 + if self.combo >= 50: + current_eighth = int((game_screen.current_ms - game_screen.start_ms) // eighth_in_ms) + else: + current_eighth = 0 + if note in {'5', '6', 'drumroll_tail', 'dai_drumroll_tail', 'drumroll_body', 'dai_drumroll_body'}: + draw_color = color + else: + draw_color = 255 + if note == '7': + offset = 12 + balloon = True + else: + offset = 0 + balloon = False + if drumroll_length == None: + drumroll_length = game_screen.note_type_dict[note][0].width + source_rect = ray.Rectangle(0,0,game_screen.note_type_dict[note][0].width,game_screen.note_type_dict[note][0].height) + dest_rect = ray.Rectangle(position-offset, 192, drumroll_length,game_screen.note_type_dict['1'][0].height) + ray.draw_texture_pro(game_screen.note_type_dict[note][current_eighth % 2], source_rect, dest_rect, ray.Vector2(0,0), 0, ray.Color(255, draw_color, draw_color, 255)) + if balloon: + ray.draw_texture(game_screen.note_type_dict['balloon_tail'][current_eighth % 2], position-offset+128, 192, ray.Color(255, draw_color, draw_color, 255)) + if se_note != None: + if drumroll_length == game_screen.note_type_dict[note][0].width: + drumroll_length = game_screen.texture_se_moji[se_note].width offset = 0 - balloon = False - if drumroll_length == None: - drumroll_length = game_screen.note_type_dict[note][0].width - source_rect = ray.Rectangle(0,0,game_screen.note_type_dict[note][0].width,game_screen.note_type_dict[note][0].height) - dest_rect = ray.Rectangle(position-offset, 192, drumroll_length,game_screen.note_type_dict['1'][0].height) - ray.draw_texture_pro(game_screen.note_type_dict[note][current_eighth % 2], source_rect, dest_rect, ray.Vector2(0,0), 0, ray.Color(255, draw_color, draw_color, 255)) - if balloon: - ray.draw_texture(game_screen.note_type_dict['balloon_tail'][current_eighth % 2], position-offset+128, 192, ray.Color(255, draw_color, draw_color, 255)) - if se_note != None: - if drumroll_length == game_screen.note_type_dict[note][0].width: - drumroll_length = game_screen.texture_se_moji[se_note].width - offset = 0 - else: - offset = 30 - source_rect = ray.Rectangle(0,0,game_screen.texture_se_moji[se_note].width,game_screen.texture_se_moji[se_note].height) - dest_rect = ray.Rectangle(position-offset - (game_screen.texture_se_moji[se_note].width // 2) + 64, 323, drumroll_length,game_screen.texture_se_moji[se_note].height) - ray.draw_texture_pro(game_screen.texture_se_moji[se_note], source_rect, dest_rect, ray.Vector2(0,0), 0, ray.WHITE) + else: + offset = 30 + source_rect = ray.Rectangle(0,0,game_screen.texture_se_moji[se_note].width,game_screen.texture_se_moji[se_note].height) + dest_rect = ray.Rectangle(position-offset - (game_screen.texture_se_moji[se_note].width // 2) + 64, 323, drumroll_length,game_screen.texture_se_moji[se_note].height) + ray.draw_texture_pro(game_screen.texture_se_moji[se_note], source_rect, dest_rect, ray.Vector2(0,0), 0, ray.WHITE) def draw_notes(self, game_screen): - if len(self.current_notes_draw) != 0 or len(self.current_bars) != 0: - for i in range(len(self.current_bars)-1, -1, -1): - bar = self.current_bars[i] - load_ms, pixels_per_frame = bar['load_ms'], bar['ppf'] - position = self.get_position(game_screen, load_ms, pixels_per_frame) - self.draw_note(game_screen, 'barline', position, 255, None) + if len(self.current_notes_draw) <= 0 or len(self.current_bars) <= 0: + return - for i in range(len(self.current_notes_draw)-1, -1, -1): - note = self.current_notes_draw[i] - note_type, load_ms, pixels_per_frame = note['note'], note['load_ms'], note['ppf'] - position = self.get_position(game_screen, load_ms, pixels_per_frame) - if 'popped' in note: - continue - if note_type == '5': - self.draw_drumroll(game_screen, False, position, i, note['color']) - elif note_type == '6': - self.draw_drumroll(game_screen, True, position, i, note['color']) - if note_type == '7': - self.draw_balloon(game_screen, note, position, i) - else: - self.draw_note(game_screen, note_type, position, 255, note['se_note']) + for i in range(len(self.current_bars)-1, -1, -1): + bar = self.current_bars[i] + load_ms, pixels_per_frame = bar['load_ms'], bar['ppf'] + position = self.get_position(game_screen, load_ms, pixels_per_frame) + self.draw_note(game_screen, 'barline', position, 255, None) + + for i in range(len(self.current_notes_draw)-1, -1, -1): + note = self.current_notes_draw[i] + note_type, load_ms, pixels_per_frame = note['note'], note['load_ms'], note['ppf'] + position = self.get_position(game_screen, load_ms, pixels_per_frame) + if 'popped' in note: + continue + if note_type == '5': + self.draw_drumroll(game_screen, False, position, i, note['color']) + elif note_type == '6': + self.draw_drumroll(game_screen, True, position, i, note['color']) + if note_type == '7': + self.draw_balloon(game_screen, note, position, i) + else: + self.draw_note(game_screen, note_type, position, 255, note['se_note']) def draw(self, game_screen): ray.draw_texture(game_screen.texture_lane, 332, 184, ray.WHITE) diff --git a/global_funcs.py b/global_funcs.py index caaa181..02e9ba5 100644 --- a/global_funcs.py +++ b/global_funcs.py @@ -2,6 +2,7 @@ import time import os import pyray as ray import cv2 +import math import zipfile import tempfile @@ -29,12 +30,13 @@ def load_texture_from_zip(zip_path, filename): os.remove(temp_file_path) return texture -def rounded(d): - sign = 1 if (d >= 0) else -1 - d = abs(d) - n = int(d) - if (d - n >= 0.5): n += 1 - return sign * n +def rounded(num): + sign = 1 if (num >= 0) else -1 + num = abs(num) + result = int(num) + if (num - result >= 0.5): + result += 1 + return sign * result def get_current_ms(): return rounded(time.time() * 1000) @@ -56,11 +58,33 @@ def stripComments(code): index += 1 return result -def get_pixels_per_frame(bpm, fps, time_signature, distance): - beat_duration = fps / bpm +def get_pixels_per_frame(bpm, time_signature, distance): + beat_duration = 60 / bpm total_time = time_signature * beat_duration - total_frames = fps * total_time - return (distance / total_frames) * (fps/60) + total_frames = 60 * total_time + return (distance / total_frames) + +def calculate_base_score(play_note_list): + total_notes = 0 + balloon_num = 0 + balloon_sec = 0 + balloon_count = 0 + drumroll_sec = 0 + for i in range(len(play_note_list)): + note = play_note_list[i] + if i < len(play_note_list)-1: + next_note = play_note_list[i+1] + else: + next_note = play_note_list[len(play_note_list)-1] + if note.get('note') in {'1','2','3','4'}: + total_notes += 1 + elif note.get('note') in {'5', '6'}: + drumroll_sec += (next_note.get('ms') - note.get('ms')) / 1000 + elif note.get('note') in {'7', '9'}: + balloon_num += 1 + balloon_count += next_note.get('balloon') + total_score = (1000000 - (balloon_count * 100) - (drumroll_sec * 1692.0079999994086)) / total_notes + return math.ceil(total_score / 10) * 10 class TJAParser: def __init__(self, path): @@ -87,7 +111,6 @@ class TJAParser: self.time_signature = 4/4 self.distance = 0 - self.fps = 60 self.scroll_modifier = 1 self.current_ms = 0 self.barline_display = True @@ -152,7 +175,8 @@ class TJAParser: continue item = int(item.split(':')[1]) self.course_data[diff_index+highest_diff].append(item) - return [self.title, self.title_ja, self.subtitle, self.subtitle_ja, self.bpm, self.wave, self.offset, self.demo_start, self.course_data] + return [self.title, self.title_ja, self.subtitle, self.subtitle_ja, + self.bpm, self.wave, self.offset, self.demo_start, self.course_data] def data_to_notes(self, diff): self.file_to_data() @@ -180,15 +204,8 @@ class TJAParser: bar = [] return notes, self.course_data[diff][1] - def notes_to_position(self, diff): - play_note_list = deque() - bar_list = deque() - draw_note_list = deque() - notes, balloon = self.data_to_notes(diff) - index = 0 - balloon_index = 0 - drumroll_head = dict() - drumroll_tail = dict() + def get_se_note(self, play_note_list, ms_per_measure, note, note_ms): + #Someone please refactor this se_notes = {'1': [0, 1, 2], '2': [3, 4], '3': 5, @@ -198,6 +215,39 @@ class TJAParser: '7': 9, '8': 10, '9': 11} + if len(play_note_list) > 1: + prev_note = play_note_list[-2] + if prev_note['note'] in {'1', '2'}: + if note_ms - prev_note['ms'] <= (ms_per_measure/8) - 1: + prev_note['se_note'] = se_notes[prev_note['note']][1] + else: + prev_note['se_note'] = se_notes[prev_note['note']][0] + else: + prev_note['se_note'] = se_notes[prev_note['note']] + if len(play_note_list) > 3: + if play_note_list[-4]['note'] == play_note_list[-3]['note'] == play_note_list[-2]['note'] == '1': + if (play_note_list[-3]['ms'] - play_note_list[-4]['ms'] < (ms_per_measure/8)) and (play_note_list[-2]['ms'] - play_note_list[-3]['ms'] < (ms_per_measure/8)): + if len(play_note_list) > 5: + if (play_note_list[-4]['ms'] - play_note_list[-5]['ms'] >= (ms_per_measure/8)) and (play_note_list[-1]['ms'] - play_note_list[-2]['ms'] >= (ms_per_measure/8)): + play_note_list[-3]['se_note'] = se_notes[play_note_list[-3]['note']][2] + else: + play_note_list[-3]['se_note'] = se_notes[play_note_list[-3]['note']][2] + else: + play_note_list[-1]['se_note'] = se_notes[note] + if play_note_list[-1]['note'] in {'1', '2'}: + play_note_list[-1]['se_note'] = se_notes[note][0] + else: + play_note_list[-1]['se_note'] = se_notes[note] + + def notes_to_position(self, diff): + play_note_list = deque() + bar_list = deque() + draw_note_list = deque() + notes, balloon = self.data_to_notes(diff) + index = 0 + balloon_index = 0 + drumroll_head = dict() + drumroll_tail = dict() for bar in notes: #Length of the bar is determined by number of notes excluding commands bar_length = sum(len(part) for part in bar if '#' not in part) @@ -239,8 +289,8 @@ class TJAParser: ms_per_measure = 60000 * (self.time_signature*4) / self.bpm #Determines how quickly the notes need to move across the screen to reach the judgment circle in time - pixels_per_frame = get_pixels_per_frame(self.bpm * self.time_signature * self.scroll_modifier, self.fps, self.time_signature*4, self.distance) - pixels_per_ms = pixels_per_frame / (1000 / self.fps) + pixels_per_frame = get_pixels_per_frame(self.bpm * self.time_signature * self.scroll_modifier, self.time_signature*4, self.distance) + pixels_per_ms = pixels_per_frame / (1000 / 60) bar_ms = self.current_ms load_ms = bar_ms - (self.distance / pixels_per_ms) @@ -261,32 +311,7 @@ class TJAParser: #Do not add blank notes otherwise lag if note != '0': play_note_list.append({'note': note, 'ms': note_ms, 'load_ms': load_ms, 'ppf': pixels_per_frame, 'index': index}) - - ### This needs to be moved to its own function later - if len(play_note_list) > 1: - prev_note = play_note_list[-2] - if prev_note['note'] in {'1', '2'}: - if note_ms - prev_note['ms'] <= (ms_per_measure/8) - 1: - prev_note['se_note'] = se_notes[prev_note['note']][1] - else: - prev_note['se_note'] = se_notes[prev_note['note']][0] - else: - prev_note['se_note'] = se_notes[prev_note['note']] - if len(play_note_list) > 3: - if play_note_list[-4]['note'] == play_note_list[-3]['note'] == play_note_list[-2]['note'] == '1': - if (play_note_list[-3]['ms'] - play_note_list[-4]['ms'] < (ms_per_measure/8)) and (play_note_list[-2]['ms'] - play_note_list[-3]['ms'] < (ms_per_measure/8)): - if len(play_note_list) > 5: - if (play_note_list[-4]['ms'] - play_note_list[-5]['ms'] >= (ms_per_measure/8)) and (play_note_list[-1]['ms'] - play_note_list[-2]['ms'] >= (ms_per_measure/8)): - play_note_list[-3]['se_note'] = se_notes[play_note_list[-3]['note']][2] - else: - play_note_list[-3]['se_note'] = se_notes[play_note_list[-3]['note']][2] - else: - play_note_list[-1]['se_note'] = se_notes[note] - if play_note_list[-1]['note'] in {'1', '2'}: - play_note_list[-1]['se_note'] = se_notes[note][0] - else: - play_note_list[-1]['se_note'] = se_notes[note] - + self.get_se_note(play_note_list, ms_per_measure, note, note_ms) index += 1 if note in {'5', '6', '8'}: play_note_list[-1]['color'] = 255 @@ -305,6 +330,7 @@ class TJAParser: draw_note_list = deque(sorted(play_note_list, key=lambda d: d['load_ms'])) bar_list = deque(sorted(bar_list, key=lambda d: d['load_ms'])) return play_note_list, draw_note_list, bar_list + class Animation: def __init__(self, current_ms, duration, type): self.type = type @@ -394,7 +420,6 @@ class Animation: current_opacity = initial_opacity + (final_opacity - initial_opacity) * progress self.attribute = current_opacity - def move(self, current_ms, duration, total_distance, start_position, delay): elapsed_time = current_ms - self.start_ms if elapsed_time < delay: @@ -407,7 +432,6 @@ class Animation: else: self.attribute = start_position + total_distance self.is_finished = True - def texture_change(self, current_ms, duration, textures): elapsed_time = current_ms - self.start_ms if elapsed_time <= duration: @@ -478,16 +502,6 @@ class VideoPlayer: print(len(self.frames), total_frames) def convert_frames(self): - ''' - if ray.file_exists(path[:-4] + '.pkl'): - self.object_file = path[:-4] + '.pkl' - with open(self.object_file, 'rb') as f: - self.frames = pickle.load(f) - print(f"Loaded {path[:-4] + '.pkl'}") - else: - self.object_file = None - if self.object_file is None: - ''' if not self.cap.isOpened(): raise ValueError("Error: Could not open video file.") @@ -507,36 +521,41 @@ class VideoPlayer: self.cap.release() print(f"Extracted {len(self.frames)} frames.") - ''' - with open(path[:-4] + '.pkl', 'wb') as f: - pickle.dump(self.frames, f) - ''' self.start_ms = get_current_ms() - def update(self): + def check_for_start(self): if self.start_ms is None: self.start_ms = get_current_ms() ray.play_music_stream(self.audio) if self.frames == []: self.convert_frames() + + def audio_manager(self): ray.update_music_stream(self.audio) time_played = ray.get_music_time_played(self.audio) / ray.get_music_time_length(self.audio) - if time_played > 0.95: + ending_lenience = 0.95 + if time_played > ending_lenience: self.is_finished[1] = True + def update(self): + self.check_for_start() + self.audio_manager() + if self.frame_index == len(self.frames)-1: self.is_finished[0] = True return - timestamp, frame = self.frames[self.frame_index][0], self.frames[self.frame_index][1] - if self.start_ms is not None: - elapsed_time = get_current_ms() - self.start_ms - if elapsed_time >= timestamp: - self.current_frame = ray.load_texture_from_image(frame) - if self.last_frame != self.current_frame and self.last_frame is not None: - ray.unload_texture(self.last_frame) - self.frame_index += 1 - self.last_frame = self.current_frame + if self.start_ms is None: + return + + timestamp, frame = self.frames[self.frame_index][0], self.frames[self.frame_index][1] + elapsed_time = get_current_ms() - self.start_ms + if elapsed_time >= timestamp: + self.current_frame = ray.load_texture_from_image(frame) + if self.last_frame != self.current_frame and self.last_frame is not None: + ray.unload_texture(self.last_frame) + self.frame_index += 1 + self.last_frame = self.current_frame def draw(self): if self.current_frame is not None: diff --git a/title.py b/title.py index 9f96652..f5c4d48 100644 --- a/title.py +++ b/title.py @@ -1,6 +1,4 @@ import pyray as ray -import numpy as np -import cv2 import os import random from global_funcs import Animation, VideoPlayer, get_current_ms, load_texture_from_zip @@ -9,39 +7,39 @@ class TitleScreen: def __init__(self, width, height): self.width = width self.height = height - self.op_videos = [] + self.op_video_list = [] for root, folder, files in os.walk('Videos\\op_videos'): for file in files: if file.endswith('.mp4'): - self.op_videos.append(VideoPlayer(root + '\\' + file)) - self.current_op_video = random.choice(self.op_videos) - self.attract_videos = [] + self.op_video_list.append(VideoPlayer(root + '\\' + file)) + self.op_video = random.choice(self.op_video_list) + self.attract_video_list = [] for root, folder, files in os.walk('Videos\\attract_videos'): for file in files: if file.endswith('.mp4'): - self.attract_videos.append(VideoPlayer(root + '\\' + file)) - self.current_attract_video = None - self.warning = None - self.scene = None + self.attract_video_list.append(VideoPlayer(root + '\\' + file)) + self.attract_video = random.choice(self.attract_video_list) + self.scene = 'Opening Video' self.load_textures() + self.warning_board = WarningBoard(get_current_ms(), self) def load_textures(self): zip_file = 'Graphics\\lumendata\\attract\\keikoku.zip' self.texture_bg = load_texture_from_zip(zip_file, 'keikoku_img00000.png') self.texture_warning = load_texture_from_zip(zip_file, 'keikoku_img00001.png') self.texture_warning_ch1 = [load_texture_from_zip(zip_file, 'keikoku_img00004.png'), - load_texture_from_zip(zip_file, 'keikoku_img00009.png'), - load_texture_from_zip(zip_file, 'keikoku_img00016.png')] + load_texture_from_zip(zip_file, 'keikoku_img00009.png'), + load_texture_from_zip(zip_file, 'keikoku_img00016.png')] self.texture_warning_ch1_base = load_texture_from_zip(zip_file, 'keikoku_img00002.png') self.texture_warning_ch2 = [load_texture_from_zip(zip_file, 'keikoku_img00005.png'), - load_texture_from_zip(zip_file, 'keikoku_img00006.png'), - load_texture_from_zip(zip_file, 'keikoku_img00007.png'), - load_texture_from_zip(zip_file, 'keikoku_img00008.png'), - load_texture_from_zip(zip_file, 'keikoku_img00010.png'), - load_texture_from_zip(zip_file, 'keikoku_img00011.png'), - load_texture_from_zip(zip_file, 'keikoku_img00012.png'), - load_texture_from_zip(zip_file, 'keikoku_img00013.png'), - load_texture_from_zip(zip_file, 'keikoku_img00017.png')] + load_texture_from_zip(zip_file, 'keikoku_img00006.png'), + load_texture_from_zip(zip_file, 'keikoku_img00007.png'), + load_texture_from_zip(zip_file, 'keikoku_img00008.png'), + load_texture_from_zip(zip_file, 'keikoku_img00010.png'), + load_texture_from_zip(zip_file, 'keikoku_img00011.png'), + load_texture_from_zip(zip_file, 'keikoku_img00012.png'), + load_texture_from_zip(zip_file, 'keikoku_img00013.png'), + load_texture_from_zip(zip_file, 'keikoku_img00017.png')] self.texture_warning_ch2_base = load_texture_from_zip(zip_file, 'keikoku_img00003.png') self.texture_warning_bachi = load_texture_from_zip(zip_file, 'keikoku_img00019.png') self.texture_warning_bachi_hit = load_texture_from_zip(zip_file, 'keikoku_img00018.png') @@ -49,7 +47,6 @@ class TitleScreen: self.texture_warning_x_1 = load_texture_from_zip(zip_file, 'keikoku_img00014.png') self.texture_warning_x_2 = load_texture_from_zip(zip_file, 'keikoku_img00015.png') - self.sound_bachi_swipe = ray.load_sound('Sounds\\title\\SE_ATTRACT_2.ogg') self.sound_bachi_hit = ray.load_sound('Sounds\\title\\SE_ATTRACT_3.ogg') self.sound_warning_message = ray.load_sound('Sounds\\title\\VO_ATTRACT_3.ogg') @@ -58,42 +55,37 @@ class TitleScreen: self.texture_black = load_texture_from_zip('Graphics\\lumendata\\attract\\movie.zip', 'movie_img00000.png') def scene_manager(self): - if self.current_op_video is not None: - self.scene = 'Opening Video' - self.current_op_video.update() - if all(self.current_op_video.is_finished): - self.current_op_video = None - self.warning = WarningBoard(get_current_ms(), self) - elif self.warning is not None: - self.scene = 'Warning Board' - self.warning.update(get_current_ms(), self) - if self.warning.is_finished: - self.warning = None - self.current_attract_video = random.choice(self.attract_videos) - elif self.current_attract_video is not None: - self.scene = 'Attract Video' - self.current_attract_video.update() - if all(self.current_attract_video.is_finished): - self.current_attract_video = None - self.current_op_video = random.choice(self.op_videos) - + if self.scene == 'Opening Video': + self.op_video.update() + if all(self.op_video.is_finished): + self.scene = 'Warning Board' + self.warning_board = WarningBoard(get_current_ms(), self) + elif self.scene == 'Warning Board': + self.warning_board.update(get_current_ms(), self) + if self.warning_board.is_finished: + self.scene = 'Attract Video' + self.attract_video = random.choice(self.attract_video_list) + elif self.scene == 'Attract Video': + self.attract_video.update() + if all(self.attract_video.is_finished): + self.scene = 'Opening Video' + self.op_video = random.choice(self.op_video_list) def update(self): self.scene_manager() if ray.is_key_pressed(ray.KeyboardKey.KEY_ENTER): return "ENTRY" - return None def draw(self): - if self.current_op_video is not None: - self.current_op_video.draw() - elif self.warning is not None: + if self.scene == 'Opening Video': + self.op_video.draw() + elif self.scene == 'Warning Board': bg_source = ray.Rectangle(0, 0, self.texture_bg.width, self.texture_bg.height) bg_dest = ray.Rectangle(0, 0, self.width, self.height) ray.draw_texture_pro(self.texture_bg, bg_source, bg_dest, ray.Vector2(0,0), 0, ray.WHITE) - self.warning.draw(self) - elif self.current_attract_video is not None: - self.current_attract_video.draw() + self.warning_board.draw(self) + elif self.scene == 'Attract Video': + self.attract_video.draw() ray.draw_text(f"Scene: {self.scene}", 20, 40, 20, ray.BLUE)