Add animation restart method and new backgrounds

This commit adds a new `restart()` method to animation classes to properly
reset their state, avoiding the need to recreate animations. It also adds
several new background variations and improves background selection.
This commit is contained in:
Yonokid
2025-06-18 23:11:17 -04:00
parent 6c8cdb9fad
commit c1081d255b
8 changed files with 354 additions and 68 deletions

View File

@@ -23,6 +23,10 @@ class BaseAnimation():
"""Update the animation based on the current time."""
pass
def restart(self) -> None:
self.start_ms = get_current_ms()
self.is_finished = False
def _ease_in(self, progress: float, ease_type: str) -> float:
if ease_type == "quadratic":
return progress * progress
@@ -57,9 +61,18 @@ class FadeAnimation(BaseAnimation):
super().__init__(duration, delay)
self.initial_opacity = initial_opacity
self.final_opacity = final_opacity
self.initial_opacity_saved = initial_opacity
self.final_opacity_saved = final_opacity
self.ease_in = ease_in
self.ease_out = ease_out
self.reverse_delay = reverse_delay
self.reverse_delay_saved = reverse_delay
def restart(self):
super().restart()
self.reverse_delay = self.reverse_delay_saved
self.initial_opacity = self.initial_opacity_saved
self.final_opacity = self.final_opacity_saved
def update(self, current_time_ms: float):
elapsed_time = current_time_ms - self.start_ms
@@ -90,11 +103,20 @@ class MoveAnimation(BaseAnimation):
ease_in: Optional[str] = None, ease_out: Optional[str] = None):
super().__init__(duration, delay)
self.reverse_delay = reverse_delay
self.reverse_delay_saved = reverse_delay
self.total_distance = total_distance
self.start_position = start_position
self.total_distance_saved = total_distance
self.start_position_saved = start_position
self.ease_in = ease_in
self.ease_out = ease_out
def restart(self):
super().restart()
self.reverse_delay = self.reverse_delay_saved
self.total_distance = self.total_distance_saved
self.start_position = self.start_position_saved
def update(self, current_time_ms: float):
elapsed_time = current_time_ms - self.start_ms
if elapsed_time < self.delay:
@@ -120,6 +142,7 @@ class TextureChangeAnimation(BaseAnimation):
super().__init__(duration)
self.textures = textures
self.delay = delay
def update(self, current_time_ms: float):
elapsed_time = current_time_ms - self.start_ms - self.delay
if elapsed_time <= self.duration:
@@ -151,6 +174,16 @@ class TextureResizeAnimation(BaseAnimation):
self.initial_size = initial_size
self.final_size = final_size
self.reverse_delay = reverse_delay
self.initial_size_saved = initial_size
self.final_size_saved = final_size
self.reverse_delay_saved = reverse_delay
def restart(self):
super().restart()
self.reverse_delay = self.reverse_delay_saved
self.initial_size = self.initial_size_saved
self.final_size = self.final_size_saved
def update(self, current_time_ms: float):
elapsed_time = current_time_ms - self.start_ms

View File

@@ -12,7 +12,7 @@ class Background:
self.screen_width = screen_width
self.screen_height = screen_height
self.donbg = DonBG.create(self.screen_width, self.screen_height, random.randint(6, 6), 1)
self.bg_normal = BGNormal.create(self.screen_width, self.screen_height, 1)
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.footer = Footer(self.screen_width, self.screen_height, random.randint(1, 3))
self.is_clear = False
@@ -50,7 +50,7 @@ class DonBGBase:
self.is_clear = is_clear
self.move.update(current_time_ms)
if self.move.is_finished:
self.move = Animation.create_move(3000, start_position=0, total_distance=-self.textures[self.name + f'_{self.player_num}p'][0].width)
self.move.restart()
class DonBG1(DonBGBase):
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
@@ -60,7 +60,7 @@ class DonBG1(DonBGBase):
super().update(current_time_ms, is_clear)
self.overlay_move.update(current_time_ms)
if self.overlay_move.is_finished:
self.overlay_move = Animation.create_move(1000, start_position=0, total_distance=20, reverse_delay=0)
self.overlay_move.restart()
def draw(self):
texture_index = 0
if self.is_clear:
@@ -81,7 +81,7 @@ class DonBG6(DonBGBase):
super().update(current_time_ms, is_clear)
self.overlay_move.update(current_time_ms)
if self.overlay_move.is_finished:
self.overlay_move = Animation.create_move(1000, start_position=0, total_distance=20, reverse_delay=0)
self.overlay_move.restart()
def draw(self):
texture_index = 0
if self.is_clear:
@@ -103,7 +103,7 @@ class BGNormal:
@staticmethod
def create(screen_width: int, screen_height: int, index: int):
map = [None, BGNormal1]
map = [None, BGNormal1, BGNormal2, BGNormal3, BGNormal4, BGNormal5]
selected_obj = map[index]
return selected_obj(index, screen_width, screen_height)
@@ -117,15 +117,156 @@ class BGNormalBase:
class BGNormal1(BGNormalBase):
def __init__(self, index: int, screen_width: int, screen_height: int):
super().__init__(index, screen_width, screen_height)
self.flicker = Animation.create_fade(16.67*2, initial_opacity=0.5, final_opacity=0.25, reverse_delay=0)
self.flicker = Animation.create_fade(16.67*4, initial_opacity=0.5, final_opacity=0.4, reverse_delay=0)
def update(self, current_time_ms: float):
self.flicker.update(current_time_ms)
if self.flicker.is_finished:
self.flicker = Animation.create_fade(16.67*2, initial_opacity=0.5, final_opacity=0.25, reverse_delay=0)
self.flicker.restart()
def draw(self):
ray.draw_texture(self.textures[self.name][0], 0, 360, ray.WHITE)
ray.draw_texture(self.textures[self.name][1], 0, 360, ray.fade(ray.WHITE, self.flicker.attribute))
class BGNormal2(BGNormalBase):
def __init__(self, index: int, screen_width: int, screen_height: int):
super().__init__(index, screen_width, screen_height)
self.flicker = Animation.create_fade(16.67*4, initial_opacity=0.5, final_opacity=0.4, reverse_delay=0)
def update(self, current_time_ms: float):
self.flicker.update(current_time_ms)
if self.flicker.is_finished:
self.flicker.restart()
def draw(self):
ray.draw_texture(self.textures[self.name][0], 0, 360, ray.WHITE)
ray.draw_texture(self.textures[self.name][1], 0, 360, ray.fade(ray.WHITE, self.flicker.attribute))
class BGNormal3(BGNormalBase):
def __init__(self, index: int, screen_width: int, screen_height: int):
super().__init__(index, screen_width, screen_height)
self.flicker = Animation.create_fade(16.67*10, initial_opacity=0.5, final_opacity=0.4, reverse_delay=0)
def update(self, current_time_ms):
self.flicker.update(current_time_ms)
if self.flicker.is_finished:
self.flicker.restart()
def draw(self):
src = ray.Rectangle(0, 0, self.textures[self.name][0].width, self.textures[self.name][0].height)
dest = ray.Rectangle(0, 360, self.screen_width, self.textures[self.name][0].height)
ray.draw_texture_pro(self.textures[self.name][0], src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
ray.draw_texture(self.textures[self.name][3], (self.screen_width//2) - (self.textures[self.name][3].width//2), 360, ray.WHITE)
ray.draw_texture(self.textures[self.name][6], 0, 360, ray.WHITE)
src = ray.Rectangle(0, 0, -self.textures[self.name][7].width, self.textures[self.name][7].height)
dest = ray.Rectangle((self.screen_width//2) - 170, 490, self.textures[self.name][7].width, self.textures[self.name][7].height)
ray.draw_texture_pro(self.textures[self.name][7], src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
ray.draw_texture(self.textures[self.name][7], (self.screen_width//2) + 50, 490, ray.WHITE)
#Orange
color = ray.fade(ray.WHITE, self.flicker.attribute)
ray.draw_texture(self.textures[self.name][1], (self.screen_width//2) + 180, 300, color)
ray.draw_texture(self.textures[self.name][1], (self.screen_width//2) - 380, 300, color)
#Red Green Orange
ray.draw_texture(self.textures[self.name][2], (self.screen_width//2) - 220, 350, color)
ray.draw_texture(self.textures[self.name][4], (self.screen_width//2) - 100, 350, color)
ray.draw_texture(self.textures[self.name][1], (self.screen_width//2) + 10, 350, color)
#Yellow
ray.draw_texture(self.textures[self.name][5], (self.screen_width//2) - 220, 500, color)
ray.draw_texture(self.textures[self.name][5], (self.screen_width//2) + 10, 500, color)
ray.draw_texture(self.textures[self.name][9], (self.screen_width//2) - 320, 520, ray.WHITE)
ray.draw_texture(self.textures[self.name][10], 100, 360, ray.WHITE)
ray.draw_texture(self.textures[self.name][11], self.screen_width - 100 - self.textures[self.name][11].width, 360, ray.WHITE)
class BGNormal4(BGNormalBase):
class Petal:
def __init__(self):
self.spawn_point = self.random_excluding_range()
duration = random.randint(1400, 2000)
self.move_y = Animation.create_move(duration, total_distance=360)
self.move_x = Animation.create_move(duration, total_distance=random.randint(-300, 300))
def random_excluding_range(self):
while True:
num = random.randint(0, 1280)
if num < 260 or num > 540:
return num
def update(self, current_time_ms):
self.move_x.update(current_time_ms)
self.move_y.update(current_time_ms)
def draw(self, texture):
ray.draw_texture(texture, self.spawn_point + int(self.move_x.attribute), 360+int(self.move_y.attribute), ray.fade(ray.WHITE, 0.75))
def __init__(self, index: int, screen_width: int, screen_height: int):
super().__init__(index, screen_width, screen_height)
self.flicker = Animation.create_fade(16.67*3, initial_opacity=0.5, final_opacity=0.4, reverse_delay=0)
self.turtle_move = Animation.create_move(3333*2, start_position=screen_width+112, total_distance=-(screen_width+(112*4)))
textures = ((0, 100, 3), (100, 200, 4), (200, 300, 5), (300, 400, 6), (400, 500, 7), (500, 600, 8))
self.turtle_change = Animation.create_texture_change(600, textures=textures)
self.petals = {self.Petal(), self.Petal(), self.Petal(), self.Petal(), self.Petal()}
def update(self, current_time_ms: float):
self.flicker.update(current_time_ms)
if self.flicker.is_finished:
self.flicker.restart()
self.turtle_move.update(current_time_ms)
if self.turtle_move.is_finished:
self.turtle_move.restart()
self.turtle_change.update(current_time_ms)
if self.turtle_change.is_finished:
self.turtle_change.restart()
for petal in self.petals:
petal.update(current_time_ms)
if petal.move_y.is_finished:
self.petals.remove(petal)
self.petals.add(self.Petal())
def draw(self):
ray.draw_texture(self.textures[self.name][0], 0, 360, ray.WHITE)
ray.draw_texture(self.textures[self.name][2], self.screen_width//2 - 20, 380, ray.WHITE)
ray.draw_texture(self.textures[self.name][self.turtle_change.attribute], int(self.turtle_move.attribute), 550, ray.WHITE)
ray.draw_texture(self.textures[self.name][9], 0, 360, ray.WHITE)
for petal in self.petals:
petal.draw(self.textures[self.name][10])
class BGNormal5(BGNormalBase):
def __init__(self, index: int, screen_width: int, screen_height: int):
super().__init__(index, screen_width, screen_height)
self.flicker = Animation.create_fade(16.67*10, initial_opacity=0.75, final_opacity=0.4, reverse_delay=0)
def update(self, current_time_ms: float):
self.flicker.update(current_time_ms)
if self.flicker.is_finished:
self.flicker.restart()
def draw(self):
ray.draw_texture(self.textures[self.name][0], 0, 360, ray.WHITE)
ray.draw_texture(self.textures[self.name][13], -35, 340, ray.WHITE)
ray.draw_texture(self.textures[self.name][12], 103, 380, ray.WHITE)
ray.draw_texture(self.textures[self.name][11], 241, 400, ray.WHITE)
ray.draw_texture(self.textures[self.name][10], 380, 380, ray.WHITE)
ray.draw_texture(self.textures[self.name][9], 518, 340, ray.WHITE)
ray.draw_texture(self.textures[self.name][4], 657, 340, ray.WHITE)
ray.draw_texture(self.textures[self.name][5], 795, 380, ray.WHITE)
ray.draw_texture(self.textures[self.name][6], 934, 400, ray.WHITE)
ray.draw_texture(self.textures[self.name][7], 1072, 380, ray.WHITE)
ray.draw_texture(self.textures[self.name][8], 1211, 340, ray.WHITE)
color = ray.fade(ray.WHITE, self.flicker.attribute)
ray.draw_texture(self.textures[self.name][14], -35 - 10, 340 - 10, color)
ray.draw_texture(self.textures[self.name][14], 103 - 10, 380 - 10, color)
ray.draw_texture(self.textures[self.name][14], 241 - 10, 400 - 10, color)
ray.draw_texture(self.textures[self.name][14], 380 - 10, 380 - 10, color)
ray.draw_texture(self.textures[self.name][14], 518 - 10, 340 - 10, color)
ray.draw_texture(self.textures[self.name][14], 657 - 10, 340 - 10, color)
ray.draw_texture(self.textures[self.name][14], 795 - 10, 380 - 10, color)
ray.draw_texture(self.textures[self.name][14], 934 - 10, 400 - 10, color)
ray.draw_texture(self.textures[self.name][14], 1072 - 10, 380 - 10, color)
ray.draw_texture(self.textures[self.name][14], 1211 - 10, 340 - 10, color)
ray.draw_texture(self.textures[self.name][3], (self.screen_width//2) - (self.textures[self.name][3].width//2), 360+172, ray.fade(ray.WHITE, 0.75))
ray.draw_texture(self.textures[self.name][1], 50, 600, ray.fade(ray.WHITE, 0.75))
ray.draw_texture(self.textures[self.name][1], self.screen_width-50 - self.textures[self.name][2].width, 600, ray.fade(ray.WHITE, 0.75))
ray.draw_texture(self.textures[self.name][2], self.screen_width-50 - self.textures[self.name][2].width, 600, ray.WHITE)
ray.draw_texture(self.textures[self.name][2], 50, 600, ray.WHITE)
class BGFever:
@staticmethod
@@ -149,10 +290,10 @@ class BGFever4(BGFeverBase):
def update(self, current_time_ms: float):
self.vertical_move.update(current_time_ms)
if self.vertical_move.is_finished:
self.vertical_move = Animation.create_move(1300, start_position=0, total_distance=50, reverse_delay=0)
self.vertical_move.restart()
self.horizontal_move.update(current_time_ms)
if self.horizontal_move.is_finished:
self.horizontal_move = Animation.create_move(5000, start_position=0, total_distance=self.textures[self.name][2].width)
self.horizontal_move.restart()
def draw(self):
texture = self.textures[self.name][0]
for i in range(0, self.screen_width + texture.width, texture.width):

View File

@@ -63,7 +63,6 @@ def load_all_textures_from_zip(zip_path: Path) -> dict[str, list[ray.Texture]]:
result_dict[true_filename][index] = texture
return result_dict
def rounded(num: float) -> int:
sign = 1 if (num >= 0) else -1
num = abs(num)
@@ -114,14 +113,16 @@ def save_config(config: dict[str, Any]) -> None:
tomlkit.dump(config, f)
def is_l_don_pressed() -> bool:
keys = global_data.config["keybinds"]["left_don"]
keys = global_data.config["keys"]["left_don"]
gamepad_buttons = global_data.config["gamepad"]["left_don"]
for key in keys:
if ray.is_key_pressed(ord(key)):
return True
if ray.is_gamepad_available(0):
if ray.is_gamepad_button_pressed(0, 16):
return True
for button in gamepad_buttons:
if ray.is_gamepad_button_pressed(0, button):
return True
mid_x, mid_y = (1280//2, 720)
allowed_gestures = {ray.Gesture.GESTURE_TAP, ray.Gesture.GESTURE_DOUBLETAP}
@@ -134,14 +135,16 @@ def is_l_don_pressed() -> bool:
return False
def is_r_don_pressed() -> bool:
keys = global_data.config["keybinds"]["right_don"]
keys = global_data.config["keys"]["right_don"]
gamepad_buttons = global_data.config["gamepad"]["right_don"]
for key in keys:
if ray.is_key_pressed(ord(key)):
return True
if ray.is_gamepad_available(0):
if ray.is_gamepad_button_pressed(0, 17):
return True
for button in gamepad_buttons:
if ray.is_gamepad_button_pressed(0, button):
return True
mid_x, mid_y = (1280//2, 720)
allowed_gestures = {ray.Gesture.GESTURE_TAP, ray.Gesture.GESTURE_DOUBLETAP}
@@ -154,14 +157,16 @@ def is_r_don_pressed() -> bool:
return False
def is_l_kat_pressed() -> bool:
keys = global_data.config["keybinds"]["left_kat"]
keys = global_data.config["keys"]["left_kat"]
gamepad_buttons = global_data.config["gamepad"]["left_kat"]
for key in keys:
if ray.is_key_pressed(ord(key)):
return True
if ray.is_gamepad_available(0):
if ray.is_gamepad_button_pressed(0, 10):
return True
for button in gamepad_buttons:
if ray.is_gamepad_button_pressed(0, button):
return True
mid_x, mid_y = (1280//2, 720)
allowed_gestures = {ray.Gesture.GESTURE_TAP, ray.Gesture.GESTURE_DOUBLETAP}
@@ -174,14 +179,16 @@ def is_l_kat_pressed() -> bool:
return False
def is_r_kat_pressed() -> bool:
keys = global_data.config["keybinds"]["right_kat"]
keys = global_data.config["keys"]["right_kat"]
gamepad_buttons = global_data.config["gamepad"]["right_kat"]
for key in keys:
if ray.is_key_pressed(ord(key)):
return True
if ray.is_gamepad_available(0):
if ray.is_gamepad_button_pressed(0, 12):
return True
for button in gamepad_buttons:
if ray.is_gamepad_button_pressed(0, button):
return True
mid_x, mid_y = (1280//2, 720)
allowed_gestures = {ray.Gesture.GESTURE_TAP, ray.Gesture.GESTURE_DOUBLETAP}

View File

@@ -13,6 +13,7 @@ from libs.utils import (
is_r_don_pressed,
is_r_kat_pressed,
load_all_textures_from_zip,
load_texture_from_zip,
)
@@ -32,6 +33,7 @@ class EntryScreen:
def load_textures(self):
self.textures = load_all_textures_from_zip(Path('Graphics/lumendata/entry.zip'))
self.texture_black = load_texture_from_zip(Path('Graphics/lumendata/attract/movie.zip'), 'movie_img00000.png')
def unload_textures(self):
for group in self.textures:
@@ -42,6 +44,7 @@ class EntryScreen:
sounds_dir = Path("Sounds")
self.sound_don = audio.load_sound(sounds_dir / "inst_00_don.wav")
self.sound_kat = audio.load_sound(sounds_dir / "inst_00_katsu.wav")
self.bgm = audio.load_sound(sounds_dir / "entry" / "JINGLE_ENTRY [1].ogg")
def on_screen_start(self):
if not self.screen_init:
@@ -58,14 +61,21 @@ class EntryScreen:
self.cloud_resize = None
self.cloud_texture_change = None
self.cloud_fade = None
self.fade_out = None
self.cloud_resize_loop = Animation.create_texture_resize(200, initial_size=1.0, final_size=1.1, reverse_delay=200)
self.side_select_fade = Animation.create_fade(100, initial_opacity=0.0, final_opacity=1.0)
self.bg_flicker = Animation.create_fade(500, initial_opacity=0.5, final_opacity=0.4, reverse_delay=0)
audio.play_sound(self.bgm)
def on_screen_end(self, next_screen: str):
self.screen_init = False
self.unload_textures()
audio.stop_sound(self.bgm)
return next_screen
def handle_input(self):
if self.fade_out is not None:
return
if self.state == State.SELECT_SIDE:
if is_l_don_pressed() or is_r_don_pressed():
if self.side == 1:
@@ -89,10 +99,7 @@ class EntryScreen:
elif self.state == State.SELECT_MODE:
if is_l_don_pressed() or is_r_don_pressed():
audio.play_sound(self.sound_don)
if self.selected_box == 0:
return self.on_screen_end("SONG_SELECT")
elif self.selected_box == 1:
return self.on_screen_end("SETTINGS")
self.fade_out = Animation.create_fade(160)
if is_l_kat_pressed():
audio.play_sound(self.sound_kat)
self.selected_box = max(0, self.selected_box - 1)
@@ -102,6 +109,10 @@ class EntryScreen:
def update(self):
self.on_screen_start()
self.side_select_fade.update(get_current_ms())
self.bg_flicker.update(get_current_ms())
if self.bg_flicker.is_finished:
self.bg_flicker.restart()
if self.drum_move_1 is not None:
self.drum_move_1.update(get_current_ms())
if self.drum_move_2 is not None:
@@ -117,6 +128,13 @@ class EntryScreen:
self.cloud_resize_loop.update(get_current_ms())
if self.cloud_resize_loop.is_finished:
self.cloud_resize_loop = Animation.create_texture_resize(200, initial_size=1.0, final_size=1.1, reverse_delay=200)
if self.fade_out is not None:
self.fade_out.update(get_current_ms())
if self.fade_out.is_finished:
if self.selected_box == 0:
return self.on_screen_end("SONG_SELECT")
elif self.selected_box == 1:
return self.on_screen_end("SETTINGS")
return self.handle_input()
def draw_background(self):
@@ -130,7 +148,7 @@ class EntryScreen:
ray.draw_texture(self.textures['entry'][371], (self.width // 2) - (self.textures['entry'][371].width // 2), (self.height // 2) - (self.textures['entry'][371].height // 2) + 10, ray.WHITE)
ray.draw_texture(self.textures['entry'][372], 0, 0, ray.WHITE)
ray.draw_texture(self.textures['entry'][373], self.width - self.textures['entry'][373].width, 0, ray.WHITE)
draw_scaled_texture(self.textures['entry'][374], -7, -15, 2.0, ray.fade(ray.WHITE, 0.50))
draw_scaled_texture(self.textures['entry'][374], -7, -15, 2.0, ray.fade(ray.WHITE, self.bg_flicker.attribute))
def draw_footer(self):
ray.draw_texture(self.textures['entry'][375], 1, self.height - self.textures['entry'][375].height + 7, ray.WHITE)
@@ -139,37 +157,38 @@ class EntryScreen:
if self.state == State.SELECT_SIDE or self.side != 2:
ray.draw_texture(self.textures['entry'][377], 2 + self.textures['entry'][377].width, self.height - self.textures['entry'][376].height + 1, ray.WHITE)
def draw_side_select(self):
def draw_side_select(self, fade):
color = ray.fade(ray.WHITE, fade)
left_x, top_y, right_x, bottom_y = 238, 108, 979, 520
ray.draw_texture(self.textures['entry'][205], left_x, top_y, ray.WHITE)
ray.draw_texture(self.textures['entry'][208], right_x, top_y, ray.WHITE)
ray.draw_texture(self.textures['entry'][204], left_x, bottom_y, ray.WHITE)
ray.draw_texture(self.textures['entry'][207], right_x, bottom_y, ray.WHITE)
ray.draw_texture(self.textures['entry'][205], left_x, top_y, color)
ray.draw_texture(self.textures['entry'][208], right_x, top_y, color)
ray.draw_texture(self.textures['entry'][204], left_x, bottom_y, color)
ray.draw_texture(self.textures['entry'][207], right_x, bottom_y, color)
texture = self.textures['entry'][209]
src = ray.Rectangle(0, 0, texture.width, texture.height)
dest = ray.Rectangle(left_x + self.textures['entry'][205].width, top_y, right_x - left_x - (self.textures['entry'][205].width), texture.height)
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)
texture = self.textures['entry'][210]
src = ray.Rectangle(0, 0, texture.width, texture.height)
dest = ray.Rectangle(left_x + self.textures['entry'][205].width, bottom_y, right_x - left_x - (self.textures['entry'][205].width), texture.height)
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)
texture = self.textures['entry'][203]
src = ray.Rectangle(0, 0, texture.width, texture.height)
dest = ray.Rectangle(left_x, top_y + self.textures['entry'][205].height, texture.width, bottom_y - top_y - (self.textures['entry'][205].height))
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)
texture = self.textures['entry'][206]
src = ray.Rectangle(0, 0, texture.width, texture.height)
dest = ray.Rectangle(right_x, top_y + self.textures['entry'][205].height, texture.width, bottom_y - top_y - (self.textures['entry'][205].height))
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)
texture = self.textures['entry'][202]
src = ray.Rectangle(0, 0, texture.width, texture.height)
dest = ray.Rectangle(left_x + self.textures['entry'][205].width, top_y + self.textures['entry'][205].height, right_x - left_x - (self.textures['entry'][205].width), bottom_y - top_y - (self.textures['entry'][205].height))
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)
ray.draw_texture(self.textures['entry'][226], 384, 144, ray.WHITE)
ray.draw_texture(self.textures['entry'][226], 384, 144, color)
cursor_x = 261
cursor_texture = self.textures['entry'][230]
@@ -179,7 +198,7 @@ class EntryScreen:
flip = -1
else:
texture = self.textures['entry'][232]
ray.draw_texture(texture, 261, 400, ray.WHITE)
ray.draw_texture(texture, 261, 400, color)
if self.side == 1:
texture = self.textures['entry'][76]
@@ -187,19 +206,19 @@ class EntryScreen:
cursor_x = 512
else:
texture = self.textures['entry'][228]
ray.draw_texture(texture, 512, 400, ray.WHITE)
ray.draw_texture(self.textures['entry'][201], 512, 408, ray.WHITE)
ray.draw_texture(texture, 512, 400, color)
ray.draw_texture(self.textures['entry'][201], 512, 408, color)
if self.side == 2:
texture = self.textures['entry'][233]
cursor_x = 762
else:
texture = self.textures['entry'][227]
ray.draw_texture(texture, 762, 400, ray.WHITE)
ray.draw_texture(texture, 762, 400, color)
src = ray.Rectangle(0, 0, cursor_texture.width * flip, cursor_texture.height)
dest = ray.Rectangle(cursor_x, 400, cursor_texture.width, cursor_texture.height)
ray.draw_texture_pro(cursor_texture, src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
ray.draw_texture_pro(cursor_texture, src, dest, ray.Vector2(0, 0), 0, color)
def draw_player_drum(self):
move_x = 0
@@ -230,8 +249,9 @@ class EntryScreen:
color = ray.fade(ray.WHITE, self.cloud_fade.attribute)
draw_scaled_texture(self.textures['entry'][texture_index], x + move_x - int(160 * (scale-1)), 720 + move_y - 200 - int(160 * (scale-1)), scale, color)
def draw_mode_select(self):
def draw_mode_select(self, fade):
self.draw_player_drum()
color = ray.fade(ray.WHITE, fade)
if self.cloud_fade is not None and self.cloud_fade.is_finished:
box_width = self.textures['entry'][262].width
spacing = 80
@@ -248,31 +268,39 @@ class EntryScreen:
else:
push_offset = push_distance
final_x = x_pos + push_offset
ray.draw_texture(self.textures['entry'][262], final_x, y, ray.WHITE)
ray.draw_texture(self.textures['entry'][262], final_x, y, color)
if i == self.selected_box:
ray.draw_texture(self.textures['entry'][302], final_x, y, ray.WHITE)
ray.draw_texture(self.textures['entry'][302], final_x, y, color)
texture = self.textures['entry'][304]
src = ray.Rectangle(0, 0, texture.width, texture.height)
dest = ray.Rectangle(final_x + self.textures['entry'][302].width, y, 100 - self.textures['entry'][302].width, texture.height)
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
ray.draw_texture(self.textures['entry'][303], final_x+100, y, ray.WHITE)
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)
ray.draw_texture(self.textures['entry'][303], final_x+100, y, color)
box_title = self.box_titles[i][1]
src = ray.Rectangle(0, 0, box_title.texture.width, box_title.texture.height)
dest = ray.Rectangle(final_x + 12, y + 20, box_title.texture.width, box_title.texture.height)
box_title.draw(src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
box_title.draw(src, dest, ray.Vector2(0, 0), 0, color)
else:
box_title = self.box_titles[i][0]
src = ray.Rectangle(0, 0, box_title.texture.width, box_title.texture.height)
dest = ray.Rectangle(final_x + 9, y + 20, box_title.texture.width, box_title.texture.height)
box_title.draw(src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
box_title.draw(src, dest, ray.Vector2(0, 0), 0, color)
def draw(self):
self.draw_background()
if self.state == State.SELECT_SIDE:
self.draw_side_select()
self.draw_side_select(self.side_select_fade.attribute)
elif self.state == State.SELECT_MODE:
self.draw_mode_select()
if self.fade_out is not None:
self.draw_mode_select(self.fade_out.attribute)
else:
self.draw_mode_select(1.0)
self.draw_footer()
ray.draw_texture(self.textures['entry'][320], 0, 0, ray.WHITE)
if self.fade_out is not None and self.fade_out.is_finished:
src = ray.Rectangle(0, 0, self.texture_black.width, self.texture_black.height)
dest = ray.Rectangle(0, 0, self.width, self.height)
ray.draw_texture_pro(self.texture_black, src, dest, ray.Vector2(0, 0), 0, ray.WHITE)

View File

@@ -28,22 +28,18 @@ from libs.video import VideoPlayer
class GameScreen:
JUDGE_X = 414
SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720
def __init__(self, width: int, height: int):
self.width = width
self.height = height
self.current_ms = 0
self.result_transition = None
self.transition = None
self.song_info = None
self.screen_init = False
self.movie = None
self.end_ms = 0
self.start_delay = 1000
self.song_started = False
self.prev_touch_count = 0
self.background = Background(width, height)
def load_textures(self):
self.textures = load_all_textures_from_zip(Path('Graphics/lumendata/enso_system/common.zip'))
@@ -124,13 +120,15 @@ class GameScreen:
def on_screen_start(self):
if not self.screen_init:
self.screen_init = True
self.background = Background(self.width, self.height)
self.load_textures()
self.load_sounds()
self.init_tja(global_data.selected_song, session_data.selected_difficulty)
self.song_info = SongInfo(session_data.song_title, 'TEST')
self.result_transition = None
self.transition = Transition(self.height)
def on_screen_end(self):
def on_screen_end(self, next_screen):
self.screen_init = False
for zip in self.textures:
for texture in self.textures[zip]:
@@ -140,7 +138,7 @@ class GameScreen:
self.song_started = False
self.end_ms = 0
self.movie = None
return 'RESULT'
return next_screen
def write_score(self):
if global_data.config['general']['autoplay']:
@@ -167,6 +165,8 @@ class GameScreen:
def update(self):
self.on_screen_start()
if self.transition is not None:
self.transition.update(get_current_ms())
self.current_ms = get_current_ms() - self.start_ms
if (self.current_ms >= self.tja.metadata.offset*1000 + self.start_delay - global_data.config["general"]["judge_offset"]) and not self.song_started:
if self.song_music is not None:
@@ -188,7 +188,7 @@ class GameScreen:
if self.result_transition is not None:
self.result_transition.update(get_current_ms())
if self.result_transition.is_finished:
return self.on_screen_end()
return self.on_screen_end('RESULT')
elif len(self.player_1.play_notes) == 0:
session_data.result_score, session_data.result_good, session_data.result_ok, session_data.result_bad, session_data.result_max_combo, session_data.result_total_drumroll = self.player_1.get_result_score()
session_data.result_gauge_length = self.player_1.gauge.gauge_length
@@ -206,6 +206,10 @@ class GameScreen:
audio.play_sound(self.sound_restart)
self.song_started = False
if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):
audio.stop_sound(self.song_music)
return self.on_screen_end('SONG_SELECT')
def draw(self):
if self.movie is not None:
self.movie.draw()
@@ -214,6 +218,8 @@ class GameScreen:
self.player_1.draw(self)
if self.song_info is not None:
self.song_info.draw(self)
if self.transition is not None:
self.transition.draw(self.height)
if self.result_transition is not None:
self.result_transition.draw(self.width, self.height, global_data.textures['shutter'][0], global_data.textures['shutter'][1])
@@ -1215,6 +1221,32 @@ class SongInfo:
dest = ray.Rectangle(text_x, text_y, self.song_title.texture.width, self.song_title.texture.height)
self.song_title.draw(src, dest, ray.Vector2(0, 0), 0, self.song_name_fade)
class Transition:
def __init__(self, screen_height: int) -> None:
self.is_finished = False
self.rainbow_up = Animation.create_move(266, start_position=0, total_distance=screen_height + global_data.textures['scene_change_rainbow'][2].height, ease_in='cubic')
self.chara_down = None
def update(self, current_time_ms: float):
self.rainbow_up.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)
if self.chara_down is not None:
self.chara_down.update(current_time_ms)
self.is_finished = self.chara_down.is_finished
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(texture, 76, -int(self.rainbow_up.attribute*3) - offset, ray.WHITE)
class ResultTransition:
def __init__(self, screen_height: int):
self.move = Animation.create_move(983.33, start_position=0, total_distance=screen_height//2, ease_out='quadratic')

View File

@@ -23,6 +23,7 @@ class SettingsScreen:
self.setting_index = 0
self.in_setting_edit = False
self.editing_key = False
self.editing_gamepad = False
self.temp_key_input = ""
def on_screen_start(self):
@@ -122,6 +123,23 @@ class SettingsScreen:
elif key_pressed == ray.KeyboardKey.KEY_ESCAPE:
self.editing_key = False
def handle_gamepad_binding(self, section, key):
self.editing_gamepad = True
self.temp_key_input = ""
def update_gamepad_binding(self):
"""Update gamepad binding based on input"""
button_pressed = ray.get_gamepad_button_pressed()
if button_pressed != 0:
current_header = self.headers[self.header_index]
settings = self.get_current_settings()
if settings:
setting_key, _ = settings[self.setting_index]
self.config[current_header][setting_key] = [button_pressed]
self.editing_gamepad = False
if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):
self.editing_gamepad = False
def update(self):
self.on_screen_start()
@@ -130,6 +148,10 @@ class SettingsScreen:
self.update_key_binding()
return
if self.editing_gamepad:
self.update_gamepad_binding()
return
current_header = self.headers[self.header_index]
# Exit handling
@@ -166,14 +188,18 @@ class SettingsScreen:
elif isinstance(setting_value, (int, float)):
self.handle_numeric_change(current_header, setting_key, 1)
elif isinstance(setting_value, str):
if 'keybinds' in current_header:
if 'keys' in current_header:
self.handle_key_binding(current_header, setting_key)
elif 'gamepad' in current_header:
self.handle_gamepad_binding(current_header, setting_key)
else:
self.handle_string_cycle(current_header, setting_key)
elif isinstance(setting_value, list) and len(setting_value) > 0:
if isinstance(setting_value[0], str) and len(setting_value[0]) == 1:
# Key binding
self.handle_key_binding(current_header, setting_key)
elif isinstance(setting_value[0], int):
self.handle_gamepad_binding(current_header, setting_key)
elif is_l_don_pressed():
# Modify setting value (reverse direction for numeric)
setting_key, setting_value = settings[self.setting_index]
@@ -183,7 +209,7 @@ class SettingsScreen:
elif isinstance(setting_value, (int, float)):
self.handle_numeric_change(current_header, setting_key, -1)
elif isinstance(setting_value, str):
if 'keybinds' not in current_header:
if ('keys' not in current_header) and ('gamepad' not in current_header):
self.handle_string_cycle(current_header, setting_key)
elif ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):

View File

@@ -47,7 +47,7 @@ class SongSelectScreen:
self.sound_skip = audio.load_sound(sounds_dir / 'song_select' / 'Skip.ogg')
self.sound_ura_switch = audio.load_sound(sounds_dir / 'song_select' / 'SE_SELECT [4].ogg')
audio.set_sound_volume(self.sound_ura_switch, 0.25)
#self.sound_select = audio.load_sound(sounds_dir / "song_select.wav")
self.sound_bgm = audio.load_sound(sounds_dir / "song_select" / "JINGLE_GENRE [1].ogg")
#self.sound_cancel = audio.load_sound(sounds_dir / "cancel.wav")
def on_screen_start(self):
@@ -78,22 +78,25 @@ class SongSelectScreen:
if str(global_data.selected_song) in self.navigator.all_song_files:
self.navigator.mark_crowns_dirty_for_song(self.navigator.all_song_files[str(global_data.selected_song)])
def on_screen_end(self):
def on_screen_end(self, next_screen):
self.screen_init = False
global_data.selected_song = self.navigator.get_current_item().path
session_data.selected_difficulty = self.selected_difficulty
audio.unload_sound(self.sound_bgm)
self.reset_demo_music()
for zip in self.textures:
for texture in self.textures[zip]:
ray.unload_texture(texture)
return "GAME"
return next_screen
def reset_demo_music(self):
if self.demo_song is not None:
audio.stop_music_stream(self.demo_song)
audio.unload_music_stream(self.demo_song)
audio.play_sound(self.sound_bgm)
self.demo_song = None
self.navigator.get_current_item().box.wait = get_current_ms()
def handle_input(self):
if self.state == State.BROWSING:
if ray.is_key_pressed(ray.KeyboardKey.KEY_LEFT_CONTROL) or (is_l_kat_pressed() and get_current_ms() <= self.last_moved + 100):
@@ -205,7 +208,7 @@ class SongSelectScreen:
if self.game_transition is not None:
self.game_transition.update(get_current_ms())
if self.game_transition.is_finished:
return self.on_screen_end()
return self.on_screen_end("GAME")
else:
self.handle_input()
@@ -224,6 +227,7 @@ class SongSelectScreen:
audio.normalize_music_stream(self.demo_song, 0.1935)
audio.seek_music_stream(self.demo_song, song.tja.metadata.demostart)
audio.play_music_stream(self.demo_song)
audio.stop_sound(self.sound_bgm)
if song.box.is_open:
current_box = song.box
if current_box.texture_index != 552 and get_current_ms() >= song.box.wait + (83.33*3):
@@ -255,6 +259,9 @@ class SongSelectScreen:
if self.ura_switch_animation is not None:
self.ura_switch_animation.update(get_current_ms())
if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):
return self.on_screen_end('ENTRY')
def draw_selector(self):
if self.selected_difficulty == -1:
ray.draw_texture(self.textures['song_select'][133], 314, 110, ray.WHITE)

View File

@@ -31,6 +31,7 @@ class TitleScreen:
self.attract_video_list = [file for file in video_dir.glob("**/*.mp4")]
self.load_sounds()
self.screen_init = False
self.fade_out = None
def get_videos(self):
return self.op_video, self.attract_video
@@ -38,7 +39,7 @@ class TitleScreen:
def load_sounds(self):
sounds_dir = Path("Sounds")
title_dir = sounds_dir / "title"
self.sound_don = audio.load_sound(sounds_dir / "inst_00_don.wav")
self.sound_bachi_swipe = audio.load_sound(title_dir / "SE_ATTRACT_2.ogg")
self.sound_bachi_hit = audio.load_sound(title_dir / "SE_ATTRACT_3.ogg")
self.sound_warning_message = audio.load_sound(title_dir / "VO_ATTRACT_3.ogg")
@@ -99,9 +100,15 @@ class TitleScreen:
def update(self):
self.on_screen_start()
if self.fade_out is not None:
self.fade_out.update(get_current_ms())
if self.fade_out.is_finished:
return self.on_screen_end()
self.scene_manager()
if is_l_don_pressed() or is_r_don_pressed():
return self.on_screen_end()
self.fade_out = Animation.create_fade(1000, initial_opacity=0.0, final_opacity=1.0)
audio.play_sound(self.sound_don)
def draw(self):
if self.state == State.OP_VIDEO:
@@ -114,6 +121,11 @@ class TitleScreen:
elif self.state == State.ATTRACT_VIDEO:
self.attract_video.draw()
if self.fade_out is not None:
src = ray.Rectangle(0, 0, self.texture_black.width, self.texture_black.height)
dest = ray.Rectangle(0, 0, self.width, self.height)
ray.draw_texture_pro(self.texture_black, src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, self.fade_out.attribute))
class WarningScreen:
class X:
DELAY = 4250