mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 11:40:13 +01:00
add new texture wrapper
This commit is contained in:
18
PyTaiko.py
18
PyTaiko.py
@@ -12,6 +12,7 @@ from raylib.defines import (
|
|||||||
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.utils import (
|
from libs.utils import (
|
||||||
|
force_dedicated_gpu,
|
||||||
get_config,
|
get_config,
|
||||||
global_data,
|
global_data,
|
||||||
load_all_textures_from_zip,
|
load_all_textures_from_zip,
|
||||||
@@ -59,6 +60,7 @@ def create_song_db():
|
|||||||
print("Scores database created successfully")
|
print("Scores database created successfully")
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
force_dedicated_gpu()
|
||||||
global_data.config = get_config()
|
global_data.config = get_config()
|
||||||
screen_width: int = global_data.config["video"]["screen_width"]
|
screen_width: int = global_data.config["video"]["screen_width"]
|
||||||
screen_height: int = global_data.config["video"]["screen_height"]
|
screen_height: int = global_data.config["video"]["screen_height"]
|
||||||
@@ -77,6 +79,7 @@ def main():
|
|||||||
|
|
||||||
ray.init_window(screen_width, screen_height, "PyTaiko")
|
ray.init_window(screen_width, screen_height, "PyTaiko")
|
||||||
global_data.textures = load_all_textures_from_zip(Path('Graphics/lumendata/intermission.zip'))
|
global_data.textures = load_all_textures_from_zip(Path('Graphics/lumendata/intermission.zip'))
|
||||||
|
global_data.tex.load_screen_textures('transition')
|
||||||
if global_data.config["video"]["borderless"]:
|
if global_data.config["video"]["borderless"]:
|
||||||
ray.toggle_borderless_windowed()
|
ray.toggle_borderless_windowed()
|
||||||
if global_data.config["video"]["fullscreen"]:
|
if global_data.config["video"]["fullscreen"]:
|
||||||
@@ -114,21 +117,22 @@ def main():
|
|||||||
ray.set_exit_key(ray.KeyboardKey.KEY_A)
|
ray.set_exit_key(ray.KeyboardKey.KEY_A)
|
||||||
|
|
||||||
while not ray.window_should_close():
|
while not ray.window_should_close():
|
||||||
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_F11):
|
||||||
|
ray.toggle_fullscreen()
|
||||||
|
elif ray.is_key_pressed(ray.KeyboardKey.KEY_F10):
|
||||||
|
ray.toggle_borderless_windowed()
|
||||||
|
|
||||||
ray.begin_texture_mode(target)
|
ray.begin_texture_mode(target)
|
||||||
ray.begin_blend_mode(ray.BlendMode.BLEND_CUSTOM_SEPARATE)
|
ray.begin_blend_mode(ray.BlendMode.BLEND_CUSTOM_SEPARATE)
|
||||||
|
|
||||||
screen = screen_mapping[current_screen]
|
screen = screen_mapping[current_screen]
|
||||||
# Begin 3D mode with orthographic camera
|
|
||||||
|
|
||||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_F11):
|
|
||||||
ray.toggle_borderless_windowed()
|
|
||||||
|
|
||||||
next_screen = screen.update()
|
next_screen = screen.update()
|
||||||
ray.clear_background(ray.BLACK)
|
ray.clear_background(ray.BLACK)
|
||||||
screen.draw()
|
screen.draw()
|
||||||
ray.begin_mode_3d(camera)
|
#ray.begin_mode_3d(camera)
|
||||||
screen.draw_3d()
|
#screen.draw_3d()
|
||||||
ray.end_mode_3d()
|
# ray.end_mode_3d()
|
||||||
|
|
||||||
if next_screen is not None:
|
if next_screen is not None:
|
||||||
current_screen = next_screen
|
current_screen = next_screen
|
||||||
|
|||||||
@@ -16,14 +16,18 @@ Windows:
|
|||||||
```
|
```
|
||||||
Run PyTaiko.exe
|
Run PyTaiko.exe
|
||||||
```
|
```
|
||||||
MacOS/Linux:
|
MacOS:
|
||||||
```
|
```
|
||||||
Good luck, would suggest running with python directly
|
Good luck, would suggest running with python directly
|
||||||
```
|
```
|
||||||
|
Linux:
|
||||||
|
```
|
||||||
|
Run PyTaiko.bin for Debian based systems, otherwise run python
|
||||||
|
```
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
https://linear.app/pytaiko
|
Ask me
|
||||||
|
|
||||||
|
|
||||||
## Known Issues
|
## Known Issues
|
||||||
|
|||||||
@@ -1,6 +1,17 @@
|
|||||||
from typing import Optional
|
import time
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
from libs.utils import get_current_ms
|
|
||||||
|
def rounded(num: float) -> int:
|
||||||
|
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() -> int:
|
||||||
|
return rounded(time.time() * 1000)
|
||||||
|
|
||||||
|
|
||||||
class BaseAnimation():
|
class BaseAnimation():
|
||||||
@@ -15,17 +26,39 @@ class BaseAnimation():
|
|||||||
"""
|
"""
|
||||||
self.duration = duration
|
self.duration = duration
|
||||||
self.delay = delay
|
self.delay = delay
|
||||||
|
self.delay_saved = delay
|
||||||
self.start_ms = get_current_ms()
|
self.start_ms = get_current_ms()
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
self.attribute = 0
|
self.attribute = 0
|
||||||
|
self.is_started = False
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self.__dict__)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.__dict__)
|
||||||
|
|
||||||
def update(self, current_time_ms: float) -> None:
|
def update(self, current_time_ms: float) -> None:
|
||||||
"""Update the animation based on the current time."""
|
"""Update the animation based on the current time."""
|
||||||
pass
|
|
||||||
|
|
||||||
def restart(self) -> None:
|
def restart(self) -> None:
|
||||||
self.start_ms = get_current_ms()
|
self.start_ms = get_current_ms()
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
|
self.delay = self.delay_saved
|
||||||
|
|
||||||
|
def start(self) -> None:
|
||||||
|
self.is_started = True
|
||||||
|
self.restart()
|
||||||
|
|
||||||
|
def pause(self):
|
||||||
|
self.is_started = False
|
||||||
|
|
||||||
|
def unpause(self):
|
||||||
|
self.is_started = True
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.restart()
|
||||||
|
self.pause()
|
||||||
|
|
||||||
def _ease_in(self, progress: float, ease_type: str) -> float:
|
def _ease_in(self, progress: float, ease_type: str) -> float:
|
||||||
if ease_type == "quadratic":
|
if ease_type == "quadratic":
|
||||||
@@ -60,6 +93,7 @@ class FadeAnimation(BaseAnimation):
|
|||||||
reverse_delay: Optional[float] = None) -> None:
|
reverse_delay: Optional[float] = None) -> None:
|
||||||
super().__init__(duration, delay)
|
super().__init__(duration, delay)
|
||||||
self.initial_opacity = initial_opacity
|
self.initial_opacity = initial_opacity
|
||||||
|
self.attribute = initial_opacity
|
||||||
self.final_opacity = final_opacity
|
self.final_opacity = final_opacity
|
||||||
self.initial_opacity_saved = initial_opacity
|
self.initial_opacity_saved = initial_opacity
|
||||||
self.final_opacity_saved = final_opacity
|
self.final_opacity_saved = final_opacity
|
||||||
@@ -73,8 +107,13 @@ class FadeAnimation(BaseAnimation):
|
|||||||
self.reverse_delay = self.reverse_delay_saved
|
self.reverse_delay = self.reverse_delay_saved
|
||||||
self.initial_opacity = self.initial_opacity_saved
|
self.initial_opacity = self.initial_opacity_saved
|
||||||
self.final_opacity = self.final_opacity_saved
|
self.final_opacity = self.final_opacity_saved
|
||||||
|
self.attribute = self.initial_opacity
|
||||||
|
|
||||||
def update(self, current_time_ms: float) -> None:
|
def update(self, current_time_ms: float) -> None:
|
||||||
|
if not self.is_started:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.is_started = not self.is_finished
|
||||||
elapsed_time = current_time_ms - self.start_ms
|
elapsed_time = current_time_ms - self.start_ms
|
||||||
|
|
||||||
if elapsed_time <= self.delay:
|
if elapsed_time <= self.delay:
|
||||||
@@ -116,8 +155,13 @@ class MoveAnimation(BaseAnimation):
|
|||||||
self.reverse_delay = self.reverse_delay_saved
|
self.reverse_delay = self.reverse_delay_saved
|
||||||
self.total_distance = self.total_distance_saved
|
self.total_distance = self.total_distance_saved
|
||||||
self.start_position = self.start_position_saved
|
self.start_position = self.start_position_saved
|
||||||
|
self.attribute = self.start_position
|
||||||
|
|
||||||
def update(self, current_time_ms: float) -> None:
|
def update(self, current_time_ms: float) -> None:
|
||||||
|
if not self.is_started:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.is_started = not self.is_finished
|
||||||
elapsed_time = current_time_ms - self.start_ms
|
elapsed_time = current_time_ms - self.start_ms
|
||||||
if elapsed_time < self.delay:
|
if elapsed_time < self.delay:
|
||||||
self.attribute = self.start_position
|
self.attribute = self.start_position
|
||||||
@@ -142,12 +186,22 @@ class TextureChangeAnimation(BaseAnimation):
|
|||||||
super().__init__(duration)
|
super().__init__(duration)
|
||||||
self.textures = textures
|
self.textures = textures
|
||||||
self.delay = delay
|
self.delay = delay
|
||||||
|
self.delay_saved = delay
|
||||||
|
|
||||||
def update(self, current_time_ms: float) -> None:
|
def update(self, current_time_ms: float) -> None:
|
||||||
elapsed_time = current_time_ms - self.start_ms - self.delay
|
super().update(current_time_ms)
|
||||||
if elapsed_time <= self.duration:
|
if not self.is_started:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.is_started = not self.is_finished
|
||||||
|
elapsed_time = current_time_ms - self.start_ms
|
||||||
|
if elapsed_time < self.delay:
|
||||||
|
return
|
||||||
|
|
||||||
|
animation_time = elapsed_time - self.delay
|
||||||
|
if animation_time <= self.duration:
|
||||||
for start, end, index in self.textures:
|
for start, end, index in self.textures:
|
||||||
if start < elapsed_time <= end:
|
if start < animation_time <= end:
|
||||||
self.attribute = index
|
self.attribute = index
|
||||||
else:
|
else:
|
||||||
self.is_finished = True
|
self.is_finished = True
|
||||||
@@ -156,6 +210,10 @@ class TextStretchAnimation(BaseAnimation):
|
|||||||
def __init__(self, duration: float) -> None:
|
def __init__(self, duration: float) -> None:
|
||||||
super().__init__(duration)
|
super().__init__(duration)
|
||||||
def update(self, current_time_ms: float) -> None:
|
def update(self, current_time_ms: float) -> None:
|
||||||
|
if not self.is_started:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.is_started = not self.is_finished
|
||||||
elapsed_time = current_time_ms - self.start_ms
|
elapsed_time = current_time_ms - self.start_ms
|
||||||
if elapsed_time <= self.duration:
|
if elapsed_time <= self.duration:
|
||||||
self.attribute = 2 + 5 * (elapsed_time // 25)
|
self.attribute = 2 + 5 * (elapsed_time // 25)
|
||||||
@@ -189,6 +247,10 @@ class TextureResizeAnimation(BaseAnimation):
|
|||||||
|
|
||||||
|
|
||||||
def update(self, current_time_ms: float) -> None:
|
def update(self, current_time_ms: float) -> None:
|
||||||
|
if not self.is_started:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.is_started = not self.is_finished
|
||||||
elapsed_time = current_time_ms - self.start_ms
|
elapsed_time = current_time_ms - self.start_ms
|
||||||
|
|
||||||
if elapsed_time <= self.delay:
|
if elapsed_time <= self.delay:
|
||||||
@@ -286,3 +348,86 @@ class Animation:
|
|||||||
reverse_delay: If provided, resize will play in reverse after this delay
|
reverse_delay: If provided, resize will play in reverse after this delay
|
||||||
"""
|
"""
|
||||||
return TextureResizeAnimation(duration, **kwargs)
|
return TextureResizeAnimation(duration, **kwargs)
|
||||||
|
|
||||||
|
ANIMATION_CLASSES = {
|
||||||
|
"fade": FadeAnimation,
|
||||||
|
"move": MoveAnimation,
|
||||||
|
"texture_change": TextureChangeAnimation,
|
||||||
|
"text_stretch": TextStretchAnimation,
|
||||||
|
"texture_resize": TextureResizeAnimation
|
||||||
|
}
|
||||||
|
|
||||||
|
def parse_animations(animation_json):
|
||||||
|
raw_anims = {}
|
||||||
|
for item in animation_json:
|
||||||
|
if "id" not in item:
|
||||||
|
raise Exception("Animation requires id")
|
||||||
|
if "type" not in item:
|
||||||
|
raise Exception("Animation requires type")
|
||||||
|
|
||||||
|
raw_anims[item["id"]] = item.copy()
|
||||||
|
|
||||||
|
def find_refs(anim_id: int, visited: Optional[set] = None):
|
||||||
|
if visited is None:
|
||||||
|
visited = set()
|
||||||
|
|
||||||
|
if anim_id in visited:
|
||||||
|
raise Exception(f"Circular reference detected involving animation {anim_id}")
|
||||||
|
|
||||||
|
visited.add(anim_id)
|
||||||
|
animation = raw_anims[anim_id].copy()
|
||||||
|
|
||||||
|
for key, value in animation.items():
|
||||||
|
if isinstance(value, dict) and "reference_id" in value:
|
||||||
|
animation[key] = resolve_value(value, visited.copy())
|
||||||
|
|
||||||
|
visited.remove(anim_id)
|
||||||
|
return animation
|
||||||
|
|
||||||
|
def resolve_value(ref_obj: dict[str, Any], visited: set):
|
||||||
|
if "property" not in ref_obj:
|
||||||
|
raise Exception("Reference requires 'property' field")
|
||||||
|
|
||||||
|
ref_id = ref_obj["reference_id"]
|
||||||
|
ref_property = ref_obj["property"]
|
||||||
|
|
||||||
|
if ref_id not in raw_anims:
|
||||||
|
raise Exception(f"Referenced animation {ref_id} not found")
|
||||||
|
|
||||||
|
resolved_ref_animation = find_refs(ref_id, visited)
|
||||||
|
|
||||||
|
if ref_property not in resolved_ref_animation:
|
||||||
|
raise Exception(f"Property '{ref_property}' not found in animation {ref_id}")
|
||||||
|
|
||||||
|
base_value = resolved_ref_animation[ref_property]
|
||||||
|
|
||||||
|
if "init_val" in ref_obj:
|
||||||
|
init_val = ref_obj["init_val"]
|
||||||
|
|
||||||
|
if isinstance(init_val, dict) and "reference_id" in init_val:
|
||||||
|
init_val = resolve_value(init_val, visited)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return base_value + init_val
|
||||||
|
except TypeError:
|
||||||
|
raise Exception(f"Cannot add init_val {init_val} to referenced value {base_value}")
|
||||||
|
|
||||||
|
return base_value
|
||||||
|
|
||||||
|
anim_dict = dict()
|
||||||
|
|
||||||
|
for id in raw_anims:
|
||||||
|
absolute_anim = find_refs(id)
|
||||||
|
type = absolute_anim.pop("type")
|
||||||
|
id_val = absolute_anim.pop("id")
|
||||||
|
if "comment" in absolute_anim:
|
||||||
|
absolute_anim.pop("comment")
|
||||||
|
if type not in ANIMATION_CLASSES:
|
||||||
|
raise Exception(f"Unknown Animation type: {type}")
|
||||||
|
|
||||||
|
anim_class = ANIMATION_CLASSES[type]
|
||||||
|
|
||||||
|
anim_object = anim_class(**absolute_anim)
|
||||||
|
anim_dict[id_val] = anim_object
|
||||||
|
|
||||||
|
return anim_dict
|
||||||
|
|||||||
138
libs/audio.py
138
libs/audio.py
@@ -17,6 +17,7 @@ from numpy import (
|
|||||||
interp,
|
interp,
|
||||||
mean,
|
mean,
|
||||||
ndarray,
|
ndarray,
|
||||||
|
ones,
|
||||||
sqrt,
|
sqrt,
|
||||||
uint8,
|
uint8,
|
||||||
zeros,
|
zeros,
|
||||||
@@ -570,23 +571,58 @@ class AudioEngine:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def _audio_callback(self, outdata: ndarray, frames: int, time: int, status: str) -> None:
|
def _audio_callback(self, outdata: ndarray, frames: int, time: int, status: str) -> None:
|
||||||
"""Callback function for the sounddevice stream"""
|
"""callback function for the sounddevice stream"""
|
||||||
if status:
|
if status:
|
||||||
print(f"Status: {status}")
|
print(f"Status: {status}")
|
||||||
|
|
||||||
# Process any new sound play requests
|
self._process_sound_queue()
|
||||||
while not self.sound_queue.empty():
|
self._process_music_queue()
|
||||||
|
|
||||||
|
# Pre-allocate output buffer (reuse if possible)
|
||||||
|
if not hasattr(self, '_output_buffer') or self._output_buffer.shape != (frames, self.output_channels):
|
||||||
|
self._output_buffer = zeros((frames, self.output_channels), dtype=float32)
|
||||||
|
else:
|
||||||
|
self._output_buffer.fill(0.0) # Clear previous data
|
||||||
|
|
||||||
|
self._mix_sounds(self._output_buffer, frames)
|
||||||
|
|
||||||
|
self._mix_music(self._output_buffer, frames)
|
||||||
|
|
||||||
|
# Apply master volume in-place
|
||||||
|
if self.master_volume != 1.0:
|
||||||
|
self._output_buffer *= self.master_volume
|
||||||
|
|
||||||
|
# Apply limiter only if needed
|
||||||
|
max_val = np_max(np_abs(self._output_buffer))
|
||||||
|
if max_val > 1.0:
|
||||||
|
self._output_buffer /= max_val
|
||||||
|
|
||||||
|
outdata[:] = self._output_buffer
|
||||||
|
|
||||||
|
def _process_sound_queue(self) -> None:
|
||||||
|
"""Process sound queue"""
|
||||||
|
sounds_to_play = []
|
||||||
try:
|
try:
|
||||||
sound_name = self.sound_queue.get_nowait()
|
while True:
|
||||||
|
sounds_to_play.append(self.sound_queue.get_nowait())
|
||||||
|
except queue.Empty:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for sound_name in sounds_to_play:
|
||||||
if sound_name in self.sounds:
|
if sound_name in self.sounds:
|
||||||
self.sounds[sound_name].play()
|
self.sounds[sound_name].play()
|
||||||
except queue.Empty:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Process any new music play requests
|
def _process_music_queue(self) -> None:
|
||||||
while not self.music_queue.empty():
|
"""Process music queue"""
|
||||||
|
music_commands = []
|
||||||
try:
|
try:
|
||||||
music_name, action, *args = self.music_queue.get_nowait()
|
while True:
|
||||||
|
music_commands.append(self.music_queue.get_nowait())
|
||||||
|
except queue.Empty:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for command in music_commands:
|
||||||
|
music_name, action, *args = command
|
||||||
if music_name in self.music_streams:
|
if music_name in self.music_streams:
|
||||||
music = self.music_streams[music_name]
|
music = self.music_streams[music_name]
|
||||||
if action == 'play':
|
if action == 'play':
|
||||||
@@ -599,64 +635,52 @@ class AudioEngine:
|
|||||||
music.resume()
|
music.resume()
|
||||||
elif action == 'seek' and args:
|
elif action == 'seek' and args:
|
||||||
music.seek(args[0])
|
music.seek(args[0])
|
||||||
except queue.Empty:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Mix all playing sounds and music
|
def _mix_sounds(self, output: ndarray, frames: int) -> None:
|
||||||
output = zeros((frames, self.output_channels), dtype=float32)
|
"""sound mixing"""
|
||||||
|
for sound in self.sounds.values():
|
||||||
|
if not sound.is_playing:
|
||||||
|
continue
|
||||||
|
|
||||||
# Mix sounds
|
|
||||||
for sound_name, sound in self.sounds.items():
|
|
||||||
if sound.is_playing:
|
|
||||||
sound_data = sound.get_frames(frames)
|
sound_data = sound.get_frames(frames)
|
||||||
|
if sound_data is None or not isinstance(sound_data, ndarray):
|
||||||
|
continue
|
||||||
|
|
||||||
# If mono sound but stereo output, duplicate to both channels
|
# Handle channel mismatch
|
||||||
if isinstance(sound_data, ndarray):
|
if sound.channels != self.output_channels:
|
||||||
if sound.channels == 1 and self.output_channels > 1:
|
sound_data = self._convert_channels(sound_data, sound.channels)
|
||||||
sound_data = column_stack([sound_data] * self.output_channels)
|
|
||||||
|
|
||||||
# Ensure sound_data matches the output format
|
|
||||||
if sound.channels > self.output_channels:
|
|
||||||
# Down-mix if needed
|
|
||||||
if self.output_channels == 1:
|
|
||||||
sound_data = mean(sound_data, axis=1)
|
|
||||||
else:
|
|
||||||
# Keep only the first output_channels
|
|
||||||
sound_data = sound_data[:, :self.output_channels]
|
|
||||||
|
|
||||||
# Add to the mix (simple additive mixing)
|
|
||||||
output += sound_data
|
output += sound_data
|
||||||
|
|
||||||
# Mix music streams
|
def _mix_music(self, output: ndarray, frames: int) -> None:
|
||||||
for music_name, music in self.music_streams.items():
|
"""music mixing"""
|
||||||
if music.is_playing:
|
for music in self.music_streams.values():
|
||||||
|
if not music.is_playing:
|
||||||
|
continue
|
||||||
|
|
||||||
music_data = music.get_frames(frames)
|
music_data = music.get_frames(frames)
|
||||||
|
if music_data is None:
|
||||||
|
continue
|
||||||
|
|
||||||
# If mono music but stereo output, duplicate to both channels
|
if music.channels != self.output_channels:
|
||||||
if music.channels == 1 and self.output_channels > 1:
|
music_data = self._convert_channels(music_data, music.channels)
|
||||||
music_data = column_stack([music_data] * self.output_channels)
|
|
||||||
|
|
||||||
# Ensure music_data matches the output format
|
|
||||||
if music.channels > self.output_channels:
|
|
||||||
# Down-mix if needed
|
|
||||||
if self.output_channels == 1:
|
|
||||||
music_data = mean(music_data, axis=1)
|
|
||||||
else:
|
|
||||||
# Keep only the first output_channels
|
|
||||||
music_data = music_data[:, :self.output_channels]
|
|
||||||
|
|
||||||
# Add to the mix
|
|
||||||
output += music_data
|
output += music_data
|
||||||
|
|
||||||
# Apply master volume
|
def _convert_channels(self, data: ndarray, input_channels: int) -> ndarray:
|
||||||
output *= self.master_volume
|
"""channel conversion with caching"""
|
||||||
|
if input_channels == self.output_channels:
|
||||||
|
return data
|
||||||
|
|
||||||
# Apply simple limiter to prevent clipping
|
if input_channels == 1 and self.output_channels > 1:
|
||||||
max_val = np_max(np_abs(output))
|
return data[:, None] * ones((1, self.output_channels), dtype=float32)
|
||||||
if max_val > 1.0:
|
elif input_channels > self.output_channels:
|
||||||
output = output / max_val
|
if self.output_channels == 1:
|
||||||
|
return mean(data, axis=1, keepdims=True)
|
||||||
|
else:
|
||||||
|
return data[:, :self.output_channels]
|
||||||
|
|
||||||
outdata[:] = output
|
return data
|
||||||
|
|
||||||
def _start_update_thread(self) -> None:
|
def _start_update_thread(self) -> None:
|
||||||
"""Start a thread to update music streams"""
|
"""Start a thread to update music streams"""
|
||||||
@@ -671,16 +695,13 @@ class AudioEngine:
|
|||||||
active_streams = [music for music in self.music_streams.values() if music.is_playing]
|
active_streams = [music for music in self.music_streams.values() if music.is_playing]
|
||||||
|
|
||||||
if not active_streams:
|
if not active_streams:
|
||||||
# Sleep longer when no streams are active
|
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for music in active_streams:
|
for music in active_streams:
|
||||||
music.update()
|
music.update()
|
||||||
|
|
||||||
# Adjust sleep based on number of active streams
|
time.sleep(0.1)
|
||||||
sleep_time = max(0.05, 0.1 / len(active_streams))
|
|
||||||
time.sleep(sleep_time)
|
|
||||||
|
|
||||||
def init_audio_device(self):
|
def init_audio_device(self):
|
||||||
if self.audio_device_ready:
|
if self.audio_device_ready:
|
||||||
@@ -770,6 +791,9 @@ class AudioEngine:
|
|||||||
if sound in self.sounds:
|
if sound in self.sounds:
|
||||||
del self.sounds[sound]
|
del self.sounds[sound]
|
||||||
|
|
||||||
|
def unload_all_sounds(self) -> None:
|
||||||
|
self.sounds.clear()
|
||||||
|
|
||||||
def normalize_sound(self, sound: str, rms: float) -> None:
|
def normalize_sound(self, sound: str, rms: float) -> None:
|
||||||
if sound in self.sounds:
|
if sound in self.sounds:
|
||||||
self.sounds[sound].normalize_vol(rms)
|
self.sounds[sound].normalize_vol(rms)
|
||||||
|
|||||||
@@ -52,12 +52,14 @@ class DonBGBase:
|
|||||||
self.name = 'donbg_a_' + str(index).zfill(2)
|
self.name = 'donbg_a_' + str(index).zfill(2)
|
||||||
self.textures = (load_all_textures_from_zip(Path(f'Graphics/lumendata/enso_original/{self.name}_{self.player_num}p.zip')))
|
self.textures = (load_all_textures_from_zip(Path(f'Graphics/lumendata/enso_original/{self.name}_{self.player_num}p.zip')))
|
||||||
self.move = Animation.create_move(3000, start_position=0, total_distance=-self.textures[self.name + f'_{self.player_num}p'][0].width)
|
self.move = Animation.create_move(3000, start_position=0, total_distance=-self.textures[self.name + f'_{self.player_num}p'][0].width)
|
||||||
|
self.move.start()
|
||||||
self.is_clear = False
|
self.is_clear = False
|
||||||
self.clear_fade = None
|
self.clear_fade = None
|
||||||
|
|
||||||
def update(self, current_time_ms: float, is_clear: bool):
|
def update(self, current_time_ms: float, is_clear: bool):
|
||||||
if not self.is_clear and is_clear:
|
if not self.is_clear and is_clear:
|
||||||
self.clear_fade = Animation.create_fade(150, initial_opacity=0.0, final_opacity=1.0)
|
self.clear_fade = Animation.create_fade(150, initial_opacity=0.0, final_opacity=1.0)
|
||||||
|
self.clear_fade.start()
|
||||||
self.is_clear = is_clear
|
self.is_clear = is_clear
|
||||||
self.move.update(current_time_ms)
|
self.move.update(current_time_ms)
|
||||||
if self.clear_fade is not None:
|
if self.clear_fade is not None:
|
||||||
@@ -74,6 +76,7 @@ class DonBG1(DonBGBase):
|
|||||||
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||||
super().__init__(index, screen_width, screen_height, player_num)
|
super().__init__(index, screen_width, screen_height, player_num)
|
||||||
self.overlay_move = Animation.create_move(1000, start_position=0, total_distance=20, reverse_delay=0)
|
self.overlay_move = Animation.create_move(1000, start_position=0, total_distance=20, reverse_delay=0)
|
||||||
|
self.overlay_move.start()
|
||||||
def update(self, current_time_ms: float, is_clear: bool):
|
def update(self, current_time_ms: float, is_clear: bool):
|
||||||
super().update(current_time_ms, is_clear)
|
super().update(current_time_ms, is_clear)
|
||||||
self.overlay_move.update(current_time_ms)
|
self.overlay_move.update(current_time_ms)
|
||||||
@@ -100,6 +103,7 @@ class DonBG2(DonBGBase):
|
|||||||
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||||
super().__init__(index, screen_width, screen_height, player_num)
|
super().__init__(index, screen_width, screen_height, player_num)
|
||||||
self.overlay_move = Animation.create_move(1500, start_position=0, total_distance=20, reverse_delay=0)
|
self.overlay_move = Animation.create_move(1500, start_position=0, total_distance=20, reverse_delay=0)
|
||||||
|
self.overlay_move.start()
|
||||||
def update(self, current_time_ms: float, is_clear: bool):
|
def update(self, current_time_ms: float, is_clear: bool):
|
||||||
super().update(current_time_ms, is_clear)
|
super().update(current_time_ms, is_clear)
|
||||||
self.overlay_move.update(current_time_ms)
|
self.overlay_move.update(current_time_ms)
|
||||||
@@ -124,9 +128,13 @@ class DonBG3(DonBGBase):
|
|||||||
duration = 266
|
duration = 266
|
||||||
bounce_distance = 40
|
bounce_distance = 40
|
||||||
self.bounce_up = Animation.create_move(duration, total_distance=-bounce_distance, ease_out='quadratic')
|
self.bounce_up = Animation.create_move(duration, total_distance=-bounce_distance, ease_out='quadratic')
|
||||||
|
self.bounce_up.start()
|
||||||
self.bounce_down = Animation.create_move(duration, total_distance=-bounce_distance, ease_in='quadratic', delay=self.bounce_up.duration)
|
self.bounce_down = Animation.create_move(duration, total_distance=-bounce_distance, ease_in='quadratic', delay=self.bounce_up.duration)
|
||||||
|
self.bounce_down.start()
|
||||||
self.overlay_move = Animation.create_move(duration*3, total_distance=20, reverse_delay=0, ease_in='quadratic', ease_out='quadratic', delay=self.bounce_up.duration+self.bounce_down.duration)
|
self.overlay_move = Animation.create_move(duration*3, total_distance=20, reverse_delay=0, ease_in='quadratic', ease_out='quadratic', delay=self.bounce_up.duration+self.bounce_down.duration)
|
||||||
|
self.overlay_move.start()
|
||||||
self.overlay_move_2 = Animation.create_move(duration*3, total_distance=20, reverse_delay=0, ease_in='quadratic', ease_out='quadratic', delay=self.bounce_up.duration+self.bounce_down.duration+self.overlay_move.duration)
|
self.overlay_move_2 = Animation.create_move(duration*3, total_distance=20, reverse_delay=0, ease_in='quadratic', ease_out='quadratic', delay=self.bounce_up.duration+self.bounce_down.duration+self.overlay_move.duration)
|
||||||
|
self.overlay_move_2.start()
|
||||||
|
|
||||||
def update(self, current_time_ms: float, is_clear: bool):
|
def update(self, current_time_ms: float, is_clear: bool):
|
||||||
super().update(current_time_ms, is_clear)
|
super().update(current_time_ms, is_clear)
|
||||||
@@ -157,6 +165,7 @@ class DonBG4(DonBGBase):
|
|||||||
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||||
super().__init__(index, screen_width, screen_height, player_num)
|
super().__init__(index, screen_width, screen_height, player_num)
|
||||||
self.overlay_move = Animation.create_move(1500, start_position=0, total_distance=20, reverse_delay=0)
|
self.overlay_move = Animation.create_move(1500, start_position=0, total_distance=20, reverse_delay=0)
|
||||||
|
self.overlay_move.start()
|
||||||
def update(self, current_time_ms: float, is_clear: bool):
|
def update(self, current_time_ms: float, is_clear: bool):
|
||||||
super().update(current_time_ms, is_clear)
|
super().update(current_time_ms, is_clear)
|
||||||
self.overlay_move.update(current_time_ms)
|
self.overlay_move.update(current_time_ms)
|
||||||
@@ -182,8 +191,11 @@ class DonBG5(DonBGBase):
|
|||||||
duration = 266
|
duration = 266
|
||||||
bounce_distance = 40
|
bounce_distance = 40
|
||||||
self.bounce_up = Animation.create_move(duration, total_distance=-bounce_distance, ease_out='quadratic')
|
self.bounce_up = Animation.create_move(duration, total_distance=-bounce_distance, ease_out='quadratic')
|
||||||
|
self.bounce_up.start()
|
||||||
self.bounce_down = Animation.create_move(duration, total_distance=-bounce_distance, ease_in='quadratic', delay=self.bounce_up.duration)
|
self.bounce_down = Animation.create_move(duration, total_distance=-bounce_distance, ease_in='quadratic', delay=self.bounce_up.duration)
|
||||||
|
self.bounce_down.start()
|
||||||
self.adjust = Animation.create_move(1000, total_distance=10, reverse_delay=0, delay=self.bounce_up.duration+self.bounce_down.duration)
|
self.adjust = Animation.create_move(1000, total_distance=10, reverse_delay=0, delay=self.bounce_up.duration+self.bounce_down.duration)
|
||||||
|
self.adjust.start()
|
||||||
|
|
||||||
def update(self, current_time_ms: float, is_clear: bool):
|
def update(self, current_time_ms: float, is_clear: bool):
|
||||||
super().update(current_time_ms, is_clear)
|
super().update(current_time_ms, is_clear)
|
||||||
@@ -212,6 +224,7 @@ class DonBG6(DonBGBase):
|
|||||||
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||||
super().__init__(index, screen_width, screen_height, player_num)
|
super().__init__(index, screen_width, screen_height, player_num)
|
||||||
self.overlay_move = Animation.create_move(1000, start_position=0, total_distance=20, reverse_delay=0)
|
self.overlay_move = Animation.create_move(1000, start_position=0, total_distance=20, reverse_delay=0)
|
||||||
|
self.overlay_move.start()
|
||||||
def update(self, current_time_ms: float, is_clear: bool):
|
def update(self, current_time_ms: float, is_clear: bool):
|
||||||
super().update(current_time_ms, is_clear)
|
super().update(current_time_ms, is_clear)
|
||||||
self.overlay_move.update(current_time_ms)
|
self.overlay_move.update(current_time_ms)
|
||||||
@@ -260,6 +273,7 @@ class BGNormal1(BGNormalBase):
|
|||||||
def __init__(self, index: int, screen_width: int, screen_height: int):
|
def __init__(self, index: int, screen_width: int, screen_height: int):
|
||||||
super().__init__(index, screen_width, screen_height)
|
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)
|
self.flicker = Animation.create_fade(16.67*4, initial_opacity=0.5, final_opacity=0.4, reverse_delay=0)
|
||||||
|
self.flicker.start()
|
||||||
def update(self, current_time_ms: float):
|
def update(self, current_time_ms: float):
|
||||||
self.flicker.update(current_time_ms)
|
self.flicker.update(current_time_ms)
|
||||||
if self.flicker.is_finished:
|
if self.flicker.is_finished:
|
||||||
@@ -272,6 +286,7 @@ class BGNormal2(BGNormalBase):
|
|||||||
def __init__(self, index: int, screen_width: int, screen_height: int):
|
def __init__(self, index: int, screen_width: int, screen_height: int):
|
||||||
super().__init__(index, screen_width, screen_height)
|
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)
|
self.flicker = Animation.create_fade(16.67*4, initial_opacity=0.5, final_opacity=0.4, reverse_delay=0)
|
||||||
|
self.flicker.start()
|
||||||
def update(self, current_time_ms: float):
|
def update(self, current_time_ms: float):
|
||||||
self.flicker.update(current_time_ms)
|
self.flicker.update(current_time_ms)
|
||||||
if self.flicker.is_finished:
|
if self.flicker.is_finished:
|
||||||
@@ -284,6 +299,7 @@ class BGNormal3(BGNormalBase):
|
|||||||
def __init__(self, index: int, screen_width: int, screen_height: int):
|
def __init__(self, index: int, screen_width: int, screen_height: int):
|
||||||
super().__init__(index, screen_width, screen_height)
|
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)
|
self.flicker = Animation.create_fade(16.67*10, initial_opacity=0.5, final_opacity=0.4, reverse_delay=0)
|
||||||
|
self.flicker.start()
|
||||||
def update(self, current_time_ms):
|
def update(self, current_time_ms):
|
||||||
self.flicker.update(current_time_ms)
|
self.flicker.update(current_time_ms)
|
||||||
if self.flicker.is_finished:
|
if self.flicker.is_finished:
|
||||||
@@ -325,7 +341,9 @@ class BGNormal4(BGNormalBase):
|
|||||||
self.spawn_point = self.random_excluding_range()
|
self.spawn_point = self.random_excluding_range()
|
||||||
duration = random.randint(1400, 2000)
|
duration = random.randint(1400, 2000)
|
||||||
self.move_y = Animation.create_move(duration, total_distance=360)
|
self.move_y = Animation.create_move(duration, total_distance=360)
|
||||||
|
self.move_y.start()
|
||||||
self.move_x = Animation.create_move(duration, total_distance=random.randint(-300, 300))
|
self.move_x = Animation.create_move(duration, total_distance=random.randint(-300, 300))
|
||||||
|
self.move_x.start()
|
||||||
def random_excluding_range(self):
|
def random_excluding_range(self):
|
||||||
while True:
|
while True:
|
||||||
num = random.randint(0, 1280)
|
num = random.randint(0, 1280)
|
||||||
@@ -339,9 +357,12 @@ class BGNormal4(BGNormalBase):
|
|||||||
def __init__(self, index: int, screen_width: int, screen_height: int):
|
def __init__(self, index: int, screen_width: int, screen_height: int):
|
||||||
super().__init__(index, screen_width, screen_height)
|
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.flicker = Animation.create_fade(16.67*3, initial_opacity=0.5, final_opacity=0.4, reverse_delay=0)
|
||||||
|
self.flicker.start()
|
||||||
self.turtle_move = Animation.create_move(3333*2, start_position=screen_width+112, total_distance=-(screen_width+(112*4)))
|
self.turtle_move = Animation.create_move(3333*2, start_position=screen_width+112, total_distance=-(screen_width+(112*4)))
|
||||||
|
self.turtle_move.start()
|
||||||
textures = ((0, 100, 3), (100, 200, 4), (200, 300, 5), (300, 400, 6), (400, 500, 7), (500, 600, 8))
|
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.turtle_change = Animation.create_texture_change(600, textures=textures)
|
||||||
|
self.turtle_change.start()
|
||||||
self.petals = {self.Petal(), self.Petal(), self.Petal(), self.Petal(), self.Petal()}
|
self.petals = {self.Petal(), self.Petal(), self.Petal(), self.Petal(), self.Petal()}
|
||||||
def update(self, current_time_ms: float):
|
def update(self, current_time_ms: float):
|
||||||
self.flicker.update(current_time_ms)
|
self.flicker.update(current_time_ms)
|
||||||
@@ -372,6 +393,7 @@ class BGNormal5(BGNormalBase):
|
|||||||
def __init__(self, index: int, screen_width: int, screen_height: int):
|
def __init__(self, index: int, screen_width: int, screen_height: int):
|
||||||
super().__init__(index, screen_width, screen_height)
|
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)
|
self.flicker = Animation.create_fade(16.67*10, initial_opacity=0.75, final_opacity=0.4, reverse_delay=0)
|
||||||
|
self.flicker.start()
|
||||||
def update(self, current_time_ms: float):
|
def update(self, current_time_ms: float):
|
||||||
self.flicker.update(current_time_ms)
|
self.flicker.update(current_time_ms)
|
||||||
if self.flicker.is_finished:
|
if self.flicker.is_finished:
|
||||||
@@ -434,13 +456,17 @@ class BGFever4(BGFeverBase):
|
|||||||
def __init__(self, index: int, screen_width: int, screen_height: int):
|
def __init__(self, index: int, screen_width: int, screen_height: int):
|
||||||
super().__init__(index, screen_width, screen_height)
|
super().__init__(index, screen_width, screen_height)
|
||||||
self.vertical_move = Animation.create_move(1300, start_position=0, total_distance=50, reverse_delay=0)
|
self.vertical_move = Animation.create_move(1300, start_position=0, total_distance=50, reverse_delay=0)
|
||||||
|
self.vertical_move.start()
|
||||||
self.horizontal_move = Animation.create_move(5000, start_position=0, total_distance=self.textures[self.name][2].width)
|
self.horizontal_move = Animation.create_move(5000, start_position=0, total_distance=self.textures[self.name][2].width)
|
||||||
|
self.horizontal_move.start()
|
||||||
self.bg_texture_move_down = None
|
self.bg_texture_move_down = None
|
||||||
self.bg_texture_move_up = None
|
self.bg_texture_move_up = None
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.bg_texture_move_down = Animation.create_move(516, total_distance=400, ease_in='cubic')
|
self.bg_texture_move_down = Animation.create_move(516, total_distance=400, ease_in='cubic')
|
||||||
|
self.bg_texture_move_down.start()
|
||||||
self.bg_texture_move_up = Animation.create_move(200, total_distance=40, delay=self.bg_texture_move_down.duration, ease_out='quadratic')
|
self.bg_texture_move_up = Animation.create_move(200, total_distance=40, delay=self.bg_texture_move_down.duration, ease_out='quadratic')
|
||||||
|
self.bg_texture_move_up.start()
|
||||||
|
|
||||||
def update(self, current_time_ms: float):
|
def update(self, current_time_ms: float):
|
||||||
if self.bg_texture_move_down is not None:
|
if self.bg_texture_move_down is not None:
|
||||||
|
|||||||
126
libs/texture.py
126
libs/texture.py
@@ -1,10 +1,130 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import zipfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
|
from libs.animation import BaseAnimation, parse_animations
|
||||||
|
|
||||||
|
|
||||||
|
class Texture:
|
||||||
|
def __init__(self, name: str, texture: Union[ray.Texture, list[ray.Texture]], init_vals: dict[str, int]):
|
||||||
|
self.name = name
|
||||||
|
self.texture = texture
|
||||||
|
self.init_vals = init_vals
|
||||||
|
if isinstance(self.texture, list):
|
||||||
|
self.width = self.texture[0].width
|
||||||
|
self.height = self.texture[0].height
|
||||||
|
else:
|
||||||
|
self.width = self.texture.width
|
||||||
|
self.height = self.texture.height
|
||||||
|
self.is_frames = isinstance(self.texture, list)
|
||||||
|
|
||||||
|
self.x = 0
|
||||||
|
self.y = 0
|
||||||
|
self.x2 = self.width
|
||||||
|
self.y2 = self.height
|
||||||
|
|
||||||
class TextureWrapper:
|
class TextureWrapper:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
self.textures: dict[str, dict[str, Texture]] = dict()
|
||||||
def load_texture(self, texture: Path) -> ray.Texture:
|
self.animations: dict[int, BaseAnimation] = dict()
|
||||||
return ray.load_texture(str(texture))
|
self.graphics_path = Path("Graphics")
|
||||||
|
|
||||||
|
def unload_textures(self):
|
||||||
|
for zip in self.textures:
|
||||||
|
for file in self.textures[zip]:
|
||||||
|
tex_object = self.textures[zip][file]
|
||||||
|
if isinstance(tex_object.texture, list):
|
||||||
|
for texture in tex_object.texture:
|
||||||
|
ray.unload_texture(texture)
|
||||||
|
else:
|
||||||
|
ray.unload_texture(tex_object.texture)
|
||||||
|
|
||||||
|
def get_animation(self, index: int):
|
||||||
|
return self.animations[index]
|
||||||
|
|
||||||
|
def update_attr(self, subset: str, texture: str, attr: str, value: float | int):
|
||||||
|
tex_object = self.textures[subset][texture]
|
||||||
|
if hasattr(tex_object, attr):
|
||||||
|
setattr(tex_object, attr, tex_object.init_vals[attr] + value)
|
||||||
|
|
||||||
|
def _read_tex_obj_data(self, tex_mapping: dict, tex_object: Texture):
|
||||||
|
tex_object.x = tex_mapping.get("x", 0)
|
||||||
|
tex_object.y = tex_mapping.get("y", 0)
|
||||||
|
tex_object.x2 = tex_mapping.get("x2", tex_object.width)
|
||||||
|
tex_object.y2 = tex_mapping.get("y2", tex_object.height)
|
||||||
|
|
||||||
|
def load_screen_textures(self, screen_name: str) -> None:
|
||||||
|
self.unload_textures()
|
||||||
|
screen_path = self.graphics_path / screen_name
|
||||||
|
if (screen_path / 'animation.json').exists():
|
||||||
|
with open(screen_path / 'animation.json') as json_file:
|
||||||
|
self.animations = parse_animations(json.loads(json_file.read()))
|
||||||
|
for zip in screen_path.iterdir():
|
||||||
|
if zip.is_dir() or zip.suffix != ".zip":
|
||||||
|
continue
|
||||||
|
with zipfile.ZipFile(zip, 'r') as zip_ref:
|
||||||
|
if 'texture.json' not in zip_ref.namelist():
|
||||||
|
raise Exception(f"texture.json file missing from {zip}")
|
||||||
|
|
||||||
|
with zip_ref.open('texture.json') as json_file:
|
||||||
|
tex_mapping_data = json.loads(json_file.read().decode('utf-8'))
|
||||||
|
self.textures[zip.stem] = dict()
|
||||||
|
|
||||||
|
for tex_name in tex_mapping_data:
|
||||||
|
if f"{tex_name}/" in zip_ref.namelist():
|
||||||
|
tex_mapping = tex_mapping_data[tex_name]
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
zip_ref.extractall(temp_dir, members=[name for name in zip_ref.namelist()
|
||||||
|
if name.startswith(tex_name)])
|
||||||
|
|
||||||
|
extracted_path = Path(temp_dir) / tex_name
|
||||||
|
if extracted_path.is_dir():
|
||||||
|
frames = [ray.load_texture(str(frame)) for frame in sorted(extracted_path.iterdir(),
|
||||||
|
key=lambda x: int(x.stem)) if frame.is_file()]
|
||||||
|
else:
|
||||||
|
frames = [ray.load_texture(str(extracted_path))]
|
||||||
|
self.textures[zip.stem][tex_name] = Texture(tex_name, frames, tex_mapping)
|
||||||
|
self._read_tex_obj_data(tex_mapping, self.textures[zip.stem][tex_name])
|
||||||
|
elif f"{tex_name}.png" in zip_ref.namelist():
|
||||||
|
tex_mapping = tex_mapping_data[tex_name]
|
||||||
|
|
||||||
|
png_filename = f"{tex_name}.png"
|
||||||
|
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as temp_file:
|
||||||
|
temp_file.write(zip_ref.read(png_filename))
|
||||||
|
temp_path = temp_file.name
|
||||||
|
|
||||||
|
try:
|
||||||
|
tex = ray.load_texture(temp_path)
|
||||||
|
self.textures[zip.stem][tex_name] = Texture(tex_name, tex, tex_mapping)
|
||||||
|
self._read_tex_obj_data(tex_mapping, self.textures[zip.stem][tex_name])
|
||||||
|
finally:
|
||||||
|
os.unlink(temp_path)
|
||||||
|
else:
|
||||||
|
raise Exception(f"Texture {tex_name} was not found in {zip}")
|
||||||
|
|
||||||
|
|
||||||
|
def draw_texture(self, subset: str, texture: str, color: ray.Color=ray.WHITE, frame: int = 0, scale: float = 1.0, center: bool = False, mirror: str = '', x: int | float = 0, y: int | float = 0, x2: int | float = 0, y2: int | float = 0) -> None:
|
||||||
|
mirror_x = -1 if mirror == 'horizontal' else 1
|
||||||
|
mirror_y = -1 if mirror == 'vertical' else 1
|
||||||
|
tex_object = self.textures[subset][texture]
|
||||||
|
source_rect = ray.Rectangle(0, 0, tex_object.width * mirror_x, tex_object.height * mirror_y)
|
||||||
|
if center:
|
||||||
|
dest_rect = ray.Rectangle(tex_object.x + (tex_object.width//2) - ((tex_object.width * scale)//2) + x, tex_object.y + (tex_object.height//2) - ((tex_object.height * scale)//2) + y, tex_object.x2*scale + x2, tex_object.y2*scale + y2)
|
||||||
|
else:
|
||||||
|
dest_rect = ray.Rectangle(tex_object.x + x, tex_object.y + y, tex_object.x2*scale + x2, tex_object.y2*scale + y2)
|
||||||
|
if tex_object.is_frames:
|
||||||
|
if not isinstance(tex_object.texture, list):
|
||||||
|
raise Exception("Texture was marked as multiframe but is only 1 texture")
|
||||||
|
ray.draw_texture_pro(tex_object.texture[frame], source_rect, dest_rect, ray.Vector2(0, 0), 0, color)
|
||||||
|
else:
|
||||||
|
if isinstance(tex_object.texture, list):
|
||||||
|
raise Exception("Texture is multiframe but was called as 1 texture")
|
||||||
|
ray.draw_texture_pro(tex_object.texture, source_rect, dest_rect, ray.Vector2(0, 0), 0, color)
|
||||||
|
|
||||||
|
tex = TextureWrapper()
|
||||||
|
|||||||
125
libs/transition.py
Normal file
125
libs/transition.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import pyray as ray
|
||||||
|
|
||||||
|
from libs.animation import Animation
|
||||||
|
from libs.utils import OutlinedText, global_data
|
||||||
|
|
||||||
|
|
||||||
|
class Transition:
|
||||||
|
def __init__(self, title: str, subtitle: str) -> None:
|
||||||
|
self.is_finished = False
|
||||||
|
self.rainbow_up = global_data.tex.get_animation(0)
|
||||||
|
self.mini_up = global_data.tex.get_animation(1)
|
||||||
|
self.chara_down = global_data.tex.get_animation(2)
|
||||||
|
self.song_info_fade = global_data.tex.get_animation(3)
|
||||||
|
self.song_info_fade_out = global_data.tex.get_animation(4)
|
||||||
|
self.title = OutlinedText(title, 40, ray.WHITE, ray.BLACK, outline_thickness=5)
|
||||||
|
self.subtitle = OutlinedText(subtitle, 30, ray.WHITE, ray.BLACK, outline_thickness=5)
|
||||||
|
self.is_second = False
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.rainbow_up.start()
|
||||||
|
self.mini_up.start()
|
||||||
|
self.chara_down.start()
|
||||||
|
self.song_info_fade.start()
|
||||||
|
self.song_info_fade_out.start()
|
||||||
|
|
||||||
|
def update(self, current_time_ms: float):
|
||||||
|
self.rainbow_up.update(current_time_ms)
|
||||||
|
self.chara_down.update(current_time_ms)
|
||||||
|
self.mini_up.update(current_time_ms)
|
||||||
|
self.song_info_fade.update(current_time_ms)
|
||||||
|
self.song_info_fade_out.update(current_time_ms)
|
||||||
|
self.is_finished = self.song_info_fade.is_finished
|
||||||
|
|
||||||
|
def draw_song_info(self):
|
||||||
|
color_1 = ray.fade(ray.WHITE, self.song_info_fade.attribute)
|
||||||
|
color_2 = ray.fade(ray.WHITE, min(0.70, self.song_info_fade.attribute))
|
||||||
|
offset = 0
|
||||||
|
if self.is_second:
|
||||||
|
color_1 = ray.fade(ray.WHITE, self.song_info_fade_out.attribute)
|
||||||
|
color_2 = ray.fade(ray.WHITE, min(0.70, self.song_info_fade_out.attribute))
|
||||||
|
offset = 816 - self.rainbow_up.attribute
|
||||||
|
global_data.tex.draw_texture('rainbow_transition', 'text_bg', y=-self.rainbow_up.attribute - offset, color=color_2)
|
||||||
|
|
||||||
|
texture = self.title.texture
|
||||||
|
y = 1176 - texture.height//2 - int(self.rainbow_up.attribute) - offset
|
||||||
|
dest = ray.Rectangle(1280//2 - texture.width//2, y - 20, texture.width, texture.height)
|
||||||
|
self.title.draw(self.title.default_src, dest, ray.Vector2(0, 0), 0, color_1)
|
||||||
|
|
||||||
|
texture = self.subtitle.texture
|
||||||
|
dest = ray.Rectangle(1280//2 - texture.width//2, y + 30, texture.width, texture.height)
|
||||||
|
self.subtitle.draw(self.subtitle.default_src, dest, ray.Vector2(0, 0), 0, color_1)
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
total_offset = 0
|
||||||
|
if self.is_second:
|
||||||
|
total_offset = 816
|
||||||
|
global_data.tex.draw_texture('rainbow_transition', 'rainbow_bg_bottom', y=-self.rainbow_up.attribute - total_offset)
|
||||||
|
global_data.tex.draw_texture('rainbow_transition', 'rainbow_bg_top', y=-self.rainbow_up.attribute - total_offset)
|
||||||
|
global_data.tex.draw_texture('rainbow_transition', 'rainbow_bg', y=-self.rainbow_up.attribute - total_offset)
|
||||||
|
offset = self.chara_down.attribute
|
||||||
|
chara_offset = 0
|
||||||
|
if self.is_second:
|
||||||
|
offset = self.chara_down.attribute - self.mini_up.attribute//3
|
||||||
|
chara_offset = 408
|
||||||
|
global_data.tex.draw_texture('rainbow_transition', 'chara_left', x=-self.mini_up.attribute//2 - chara_offset, y=-self.mini_up.attribute + offset - total_offset)
|
||||||
|
global_data.tex.draw_texture('rainbow_transition', 'chara_right', x=self.mini_up.attribute//2 + chara_offset, y=-self.mini_up.attribute + offset - total_offset)
|
||||||
|
global_data.tex.draw_texture('rainbow_transition', 'chara_center', y=-self.rainbow_up.attribute + offset - total_offset)
|
||||||
|
|
||||||
|
self.draw_song_info()
|
||||||
|
|
||||||
|
class Transition2:
|
||||||
|
def __init__(self, screen_height: int, title: str, subtitle: str) -> None:
|
||||||
|
duration = 266
|
||||||
|
self.is_finished = False
|
||||||
|
self.rainbow_up = Animation.create_move(duration, start_position=0, total_distance=screen_height + global_data.textures['scene_change_rainbow'][2].height, ease_in='cubic')
|
||||||
|
self.rainbow_up.start()
|
||||||
|
self.chara_down = None
|
||||||
|
self.title = OutlinedText(title, 40, ray.WHITE, ray.BLACK, outline_thickness=5)
|
||||||
|
self.subtitle = OutlinedText(subtitle, 30, ray.WHITE, ray.BLACK, outline_thickness=5)
|
||||||
|
self.song_info_fade = Animation.create_fade(duration/2)
|
||||||
|
self.song_info_fade.start()
|
||||||
|
def update(self, current_time_ms: float):
|
||||||
|
self.rainbow_up.update(current_time_ms)
|
||||||
|
self.song_info_fade.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)
|
||||||
|
self.chara_down.start()
|
||||||
|
|
||||||
|
if self.chara_down is not None:
|
||||||
|
self.chara_down.update(current_time_ms)
|
||||||
|
self.is_finished = self.chara_down.is_finished
|
||||||
|
|
||||||
|
def draw_song_info(self):
|
||||||
|
texture = global_data.textures['scene_change_rainbow'][6]
|
||||||
|
y = 720//2 - texture.height
|
||||||
|
src = ray.Rectangle(0, 0, texture.width, texture.height)
|
||||||
|
dest = ray.Rectangle(1280//2 - (texture.width*3)//2, y, texture.width*3, texture.height*2)
|
||||||
|
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, min(0.70, self.song_info_fade.attribute)))
|
||||||
|
|
||||||
|
texture = self.title.texture
|
||||||
|
y = 720//2 - texture.height//2 - 20
|
||||||
|
src = ray.Rectangle(0, 0, texture.width, texture.height)
|
||||||
|
dest = ray.Rectangle(1280//2 - texture.width//2, y, texture.width, texture.height)
|
||||||
|
self.title.draw(src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, self.song_info_fade.attribute))
|
||||||
|
|
||||||
|
texture = self.subtitle.texture
|
||||||
|
src = ray.Rectangle(0, 0, texture.width, texture.height)
|
||||||
|
dest = ray.Rectangle(1280//2 - texture.width//2, y + 50, texture.width, texture.height)
|
||||||
|
self.subtitle.draw(src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, self.song_info_fade.attribute))
|
||||||
|
|
||||||
|
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(global_data.textures['scene_change_rainbow'][4], 142, 14 -int(self.rainbow_up.attribute*3) - offset, ray.WHITE)
|
||||||
|
ray.draw_texture(global_data.textures['scene_change_rainbow'][5], 958, 144 -int(self.rainbow_up.attribute*3) - offset, ray.WHITE)
|
||||||
|
ray.draw_texture(texture, 76, -int(self.rainbow_up.attribute*3) - offset, ray.WHITE)
|
||||||
|
|
||||||
|
self.draw_song_info()
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import ctypes
|
||||||
|
import hashlib
|
||||||
import math
|
import math
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import zipfile
|
import zipfile
|
||||||
@@ -16,7 +19,25 @@ from raylib import (
|
|||||||
SHADER_UNIFORM_VEC4,
|
SHADER_UNIFORM_VEC4,
|
||||||
)
|
)
|
||||||
|
|
||||||
#TJA Format creator is unknown. I did not create the format, but I did write the parser though.
|
from libs.texture import TextureWrapper
|
||||||
|
|
||||||
|
|
||||||
|
def force_dedicated_gpu():
|
||||||
|
"""Force Windows to use dedicated GPU for this application"""
|
||||||
|
if sys.platform == "win32":
|
||||||
|
try:
|
||||||
|
# NVIDIA Optimus
|
||||||
|
nvapi = ctypes.windll.kernel32.LoadLibraryW("nvapi64.dll")
|
||||||
|
if nvapi:
|
||||||
|
ctypes.windll.kernel32.SetEnvironmentVariableW("SHIM_MCCOMPAT", "0x800000001")
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# AMD PowerXpress
|
||||||
|
ctypes.windll.kernel32.SetEnvironmentVariableW("AMD_VULKAN_ICD", "DISABLE")
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
def get_zip_filenames(zip_path: Path) -> list[str]:
|
def get_zip_filenames(zip_path: Path) -> list[str]:
|
||||||
result = []
|
result = []
|
||||||
@@ -230,6 +251,7 @@ def reset_session():
|
|||||||
class GlobalData:
|
class GlobalData:
|
||||||
selected_song: Path = Path()
|
selected_song: Path = Path()
|
||||||
textures: dict[str, list[ray.Texture]] = field(default_factory=lambda: dict())
|
textures: dict[str, list[ray.Texture]] = field(default_factory=lambda: dict())
|
||||||
|
tex: TextureWrapper = field(default_factory=lambda: TextureWrapper())
|
||||||
songs_played: int = 0
|
songs_played: int = 0
|
||||||
config: dict = field(default_factory=lambda: dict())
|
config: dict = field(default_factory=lambda: dict())
|
||||||
song_hashes: dict[str, list[dict]] = field(default_factory=lambda: dict()) #Hash to path
|
song_hashes: dict[str, list[dict]] = field(default_factory=lambda: dict()) #Hash to path
|
||||||
@@ -239,8 +261,19 @@ class GlobalData:
|
|||||||
|
|
||||||
global_data = GlobalData()
|
global_data = GlobalData()
|
||||||
|
|
||||||
|
text_cache = set()
|
||||||
|
if not Path('cache/image').exists():
|
||||||
|
Path('cache/image').mkdir()
|
||||||
|
|
||||||
|
for file in Path('cache/image').iterdir():
|
||||||
|
text_cache.add(file.stem)
|
||||||
|
|
||||||
class OutlinedText:
|
class OutlinedText:
|
||||||
def __init__(self, text: str, font_size: int, color: ray.Color, outline_color: ray.Color, outline_thickness=5.0, vertical=False):
|
def __init__(self, text: str, font_size: int, color: ray.Color, outline_color: ray.Color, outline_thickness=5.0, vertical=False):
|
||||||
|
self.hash = self._hash_text(text, font_size, color, vertical)
|
||||||
|
if self.hash in text_cache:
|
||||||
|
self.texture = ray.load_texture(f'cache/image/{self.hash}.png')
|
||||||
|
else:
|
||||||
self.font = self._load_font_for_text(text)
|
self.font = self._load_font_for_text(text)
|
||||||
if vertical:
|
if vertical:
|
||||||
self.texture = self._create_text_vertical(text, font_size, color, ray.BLANK, self.font)
|
self.texture = self._create_text_vertical(text, font_size, color, ray.BLANK, self.font)
|
||||||
@@ -272,11 +305,31 @@ class OutlinedText:
|
|||||||
ray.set_shader_value(self.shader, outline_color_loc, outline_color_alloc, SHADER_UNIFORM_VEC4)
|
ray.set_shader_value(self.shader, outline_color_loc, outline_color_alloc, SHADER_UNIFORM_VEC4)
|
||||||
ray.set_shader_value(self.shader, texture_size_loc, texture_size, SHADER_UNIFORM_VEC2)
|
ray.set_shader_value(self.shader, texture_size_loc, texture_size, SHADER_UNIFORM_VEC2)
|
||||||
|
|
||||||
|
self.default_src = ray.Rectangle(0, 0, self.texture.width, self.texture.height)
|
||||||
|
|
||||||
|
def _hash_text(self, text: str, font_size: int, color: ray.Color, vertical: bool):
|
||||||
|
n = hashlib.sha256()
|
||||||
|
n.update(text.encode('utf-8'))
|
||||||
|
n.update(str(font_size).encode('utf-8'))
|
||||||
|
if isinstance(color, tuple):
|
||||||
|
n.update(str(color[0]).encode('utf-8'))
|
||||||
|
n.update(str(color[1]).encode('utf-8'))
|
||||||
|
n.update(str(color[2]).encode('utf-8'))
|
||||||
|
n.update(str(color[3]).encode('utf-8'))
|
||||||
|
else:
|
||||||
|
n.update(str(color.r).encode('utf-8'))
|
||||||
|
n.update(str(color.g).encode('utf-8'))
|
||||||
|
n.update(str(color.b).encode('utf-8'))
|
||||||
|
n.update(str(color.a).encode('utf-8'))
|
||||||
|
n.update(str(vertical).encode('utf-8'))
|
||||||
|
return n.hexdigest()
|
||||||
|
|
||||||
def _load_font_for_text(self, text: str) -> ray.Font:
|
def _load_font_for_text(self, text: str) -> ray.Font:
|
||||||
codepoint_count = ray.ffi.new('int *', 0)
|
codepoint_count = ray.ffi.new('int *', 0)
|
||||||
unique_codepoints = set(text)
|
unique_codepoints = set(text)
|
||||||
codepoints = ray.load_codepoints(''.join(unique_codepoints), codepoint_count)
|
codepoints = ray.load_codepoints(''.join(unique_codepoints), codepoint_count)
|
||||||
return ray.load_font_ex(str(Path('Graphics/Modified-DFPKanteiryu-XB.ttf')), 40, codepoints, 0)
|
font = ray.load_font_ex(str(Path('Graphics/Modified-DFPKanteiryu-XB.ttf')), 40, codepoints, 0)
|
||||||
|
return font
|
||||||
|
|
||||||
def _create_text_vertical(self, text: str, font_size: int, color: ray.Color, bg_color: ray.Color, font: Optional[ray.Font]=None, padding: int=10):
|
def _create_text_vertical(self, text: str, font_size: int, color: ray.Color, bg_color: ray.Color, font: Optional[ray.Font]=None, padding: int=10):
|
||||||
rotate_chars = {'-', '‐', '|', '/', '\\', 'ー', '~', '~', '(', ')', '(', ')',
|
rotate_chars = {'-', '‐', '|', '/', '\\', 'ー', '~', '~', '(', ')', '(', ')',
|
||||||
@@ -427,6 +480,7 @@ class OutlinedText:
|
|||||||
ray.WHITE)
|
ray.WHITE)
|
||||||
ray.unload_image(char_image)
|
ray.unload_image(char_image)
|
||||||
|
|
||||||
|
ray.export_image(image, f'cache/image/{self.hash}.png')
|
||||||
texture = ray.load_texture_from_image(image)
|
texture = ray.load_texture_from_image(image)
|
||||||
ray.unload_image(image)
|
ray.unload_image(image)
|
||||||
return texture
|
return texture
|
||||||
@@ -452,6 +506,7 @@ class OutlinedText:
|
|||||||
ray.WHITE)
|
ray.WHITE)
|
||||||
ray.unload_image(text_image)
|
ray.unload_image(text_image)
|
||||||
|
|
||||||
|
ray.export_image(image, f'cache/image/{self.hash}.png')
|
||||||
texture = ray.load_texture_from_image(image)
|
texture = ray.load_texture_from_image(image)
|
||||||
ray.unload_image(image)
|
ray.unload_image(image)
|
||||||
return texture
|
return texture
|
||||||
|
|||||||
426
scenes/entry.py
426
scenes/entry.py
@@ -2,18 +2,15 @@ from pathlib import Path
|
|||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.animation import Animation
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
|
from libs.texture import tex
|
||||||
from libs.utils import (
|
from libs.utils import (
|
||||||
OutlinedText,
|
OutlinedText,
|
||||||
draw_scaled_texture,
|
|
||||||
get_current_ms,
|
get_current_ms,
|
||||||
is_l_don_pressed,
|
is_l_don_pressed,
|
||||||
is_l_kat_pressed,
|
is_l_kat_pressed,
|
||||||
is_r_don_pressed,
|
is_r_don_pressed,
|
||||||
is_r_kat_pressed,
|
is_r_kat_pressed,
|
||||||
load_all_textures_from_zip,
|
|
||||||
load_texture_from_zip,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -26,19 +23,9 @@ class EntryScreen:
|
|||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
self.screen_init = False
|
self.screen_init = False
|
||||||
self.box_titles: list[tuple[OutlinedText, OutlinedText]] = [(OutlinedText('演奏ゲーム', 50, ray.WHITE, ray.Color(109, 68, 24, 255), outline_thickness=5, vertical=True),
|
|
||||||
OutlinedText('演奏ゲーム', 50, ray.WHITE, ray.BLACK, outline_thickness=5, vertical=True)),
|
|
||||||
(OutlinedText('ゲーム設定', 50, ray.WHITE, ray.Color(109, 68, 24, 255), outline_thickness=5, vertical=True),
|
|
||||||
OutlinedText('ゲーム設定', 50, ray.WHITE, ray.BLACK, outline_thickness=5, vertical=True))]
|
|
||||||
|
|
||||||
def load_textures(self):
|
def load_textures(self):
|
||||||
self.textures = load_all_textures_from_zip(Path('Graphics/lumendata/entry.zip'))
|
tex.load_screen_textures('entry')
|
||||||
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:
|
|
||||||
for texture in self.textures[group]:
|
|
||||||
ray.unload_texture(texture)
|
|
||||||
|
|
||||||
def load_sounds(self):
|
def load_sounds(self):
|
||||||
sounds_dir = Path("Sounds")
|
sounds_dir = Path("Sounds")
|
||||||
@@ -51,43 +38,44 @@ class EntryScreen:
|
|||||||
self.load_textures()
|
self.load_textures()
|
||||||
self.load_sounds()
|
self.load_sounds()
|
||||||
self.side = 1
|
self.side = 1
|
||||||
self.selected_box = 0
|
self.box_manager = BoxManager()
|
||||||
self.num_boxes = 2
|
|
||||||
self.state = State.SELECT_SIDE
|
self.state = State.SELECT_SIDE
|
||||||
self.screen_init = True
|
self.screen_init = True
|
||||||
self.drum_move_1 = None
|
self.side_select_fade = tex.get_animation(0)
|
||||||
self.drum_move_2 = None
|
self.bg_flicker = tex.get_animation(1)
|
||||||
self.drum_move_3 = None
|
self.drum_move_1 = tex.get_animation(2)
|
||||||
self.cloud_resize = None
|
self.drum_move_2 = tex.get_animation(3)
|
||||||
self.cloud_texture_change = None
|
self.drum_move_3 = tex.get_animation(4)
|
||||||
self.cloud_fade = None
|
self.cloud_resize = tex.get_animation(5)
|
||||||
self.fade_out = None
|
self.cloud_resize_loop = tex.get_animation(6)
|
||||||
self.cloud_resize_loop = Animation.create_texture_resize(200, initial_size=1.0, final_size=1.1, reverse_delay=200)
|
self.cloud_texture_change = tex.get_animation(7)
|
||||||
self.side_select_fade = Animation.create_fade(100, initial_opacity=0.0, final_opacity=1.0)
|
self.cloud_fade = tex.get_animation(8)
|
||||||
self.bg_flicker = Animation.create_fade(500, initial_opacity=0.5, final_opacity=0.4, reverse_delay=0)
|
self.cloud_resize_loop.start()
|
||||||
|
self.side_select_fade.start()
|
||||||
|
self.bg_flicker.start()
|
||||||
audio.play_sound(self.bgm)
|
audio.play_sound(self.bgm)
|
||||||
|
|
||||||
def on_screen_end(self, next_screen: str):
|
def on_screen_end(self, next_screen: str):
|
||||||
self.screen_init = False
|
self.screen_init = False
|
||||||
self.unload_textures()
|
|
||||||
audio.stop_sound(self.bgm)
|
audio.stop_sound(self.bgm)
|
||||||
|
tex.unload_textures()
|
||||||
|
audio.unload_all_sounds()
|
||||||
return next_screen
|
return next_screen
|
||||||
|
|
||||||
def handle_input(self):
|
def handle_input(self):
|
||||||
if self.fade_out is not None:
|
if self.box_manager.is_box_selected():
|
||||||
return
|
return
|
||||||
if self.state == State.SELECT_SIDE:
|
if self.state == State.SELECT_SIDE:
|
||||||
if is_l_don_pressed() or is_r_don_pressed():
|
if is_l_don_pressed() or is_r_don_pressed():
|
||||||
if self.side == 1:
|
if self.side == 1:
|
||||||
return self.on_screen_end("TITLE")
|
return self.on_screen_end("TITLE")
|
||||||
self.drum_move_1 = Animation.create_move(350, total_distance=-295, ease_out='quadratic')
|
self.drum_move_1.start()
|
||||||
self.drum_move_2 = Animation.create_move(200, total_distance=50, delay=self.drum_move_1.duration, ease_in='quadratic')
|
self.drum_move_2.start()
|
||||||
self.drum_move_3 = Animation.create_move(350, total_distance=-170, delay=self.drum_move_1.duration+self.drum_move_2.duration, ease_out='quadratic')
|
self.drum_move_3.start()
|
||||||
self.cloud_resize = Animation.create_texture_resize(350, initial_size=0.75, final_size=1.0)
|
self.cloud_resize.start()
|
||||||
self.cloud_resize_loop = Animation.create_texture_resize(200, initial_size=1.0, final_size=1.2, reverse_delay=200, delay=self.cloud_resize.duration)
|
self.cloud_resize_loop.start()
|
||||||
textures = ((0, 83.35, 45), (83.35, 166.7, 48), (166.7, 250, 49), (250, 333, 50))
|
self.cloud_texture_change.start()
|
||||||
self.cloud_texture_change = Animation.create_texture_change(333, textures=textures, delay=self.drum_move_1.duration+self.drum_move_2.duration+self.drum_move_3.duration)
|
self.cloud_fade.start()
|
||||||
self.cloud_fade = Animation.create_fade(83.35, delay=self.drum_move_1.duration+self.drum_move_2.duration+self.drum_move_3.duration+self.cloud_texture_change.duration)
|
|
||||||
self.state = State.SELECT_MODE
|
self.state = State.SELECT_MODE
|
||||||
audio.play_sound(self.sound_don)
|
audio.play_sound(self.sound_don)
|
||||||
if is_l_kat_pressed():
|
if is_l_kat_pressed():
|
||||||
@@ -99,13 +87,13 @@ class EntryScreen:
|
|||||||
elif self.state == State.SELECT_MODE:
|
elif self.state == State.SELECT_MODE:
|
||||||
if is_l_don_pressed() or is_r_don_pressed():
|
if is_l_don_pressed() or is_r_don_pressed():
|
||||||
audio.play_sound(self.sound_don)
|
audio.play_sound(self.sound_don)
|
||||||
self.fade_out = Animation.create_fade(160)
|
self.box_manager.select_box()
|
||||||
if is_l_kat_pressed():
|
if is_l_kat_pressed():
|
||||||
audio.play_sound(self.sound_kat)
|
audio.play_sound(self.sound_kat)
|
||||||
self.selected_box = max(0, self.selected_box - 1)
|
self.box_manager.move_left()
|
||||||
if is_r_kat_pressed():
|
if is_r_kat_pressed():
|
||||||
audio.play_sound(self.sound_kat)
|
audio.play_sound(self.sound_kat)
|
||||||
self.selected_box = min(self.num_boxes - 1, self.selected_box + 1)
|
self.box_manager.move_right()
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.on_screen_start()
|
self.on_screen_start()
|
||||||
@@ -113,197 +101,255 @@ class EntryScreen:
|
|||||||
self.bg_flicker.update(get_current_ms())
|
self.bg_flicker.update(get_current_ms())
|
||||||
if self.bg_flicker.is_finished:
|
if self.bg_flicker.is_finished:
|
||||||
self.bg_flicker.restart()
|
self.bg_flicker.restart()
|
||||||
if self.drum_move_1 is not None:
|
|
||||||
self.drum_move_1.update(get_current_ms())
|
self.drum_move_1.update(get_current_ms())
|
||||||
if self.drum_move_2 is not None:
|
|
||||||
self.drum_move_2.update(get_current_ms())
|
self.drum_move_2.update(get_current_ms())
|
||||||
if self.drum_move_3 is not None:
|
|
||||||
self.drum_move_3.update(get_current_ms())
|
self.drum_move_3.update(get_current_ms())
|
||||||
if self.cloud_resize is not None:
|
|
||||||
self.cloud_resize.update(get_current_ms())
|
self.cloud_resize.update(get_current_ms())
|
||||||
if self.cloud_texture_change is not None:
|
|
||||||
self.cloud_texture_change.update(get_current_ms())
|
self.cloud_texture_change.update(get_current_ms())
|
||||||
if self.cloud_fade is not None:
|
|
||||||
self.cloud_fade.update(get_current_ms())
|
self.cloud_fade.update(get_current_ms())
|
||||||
self.cloud_resize_loop.update(get_current_ms())
|
self.cloud_resize_loop.update(get_current_ms())
|
||||||
if self.cloud_resize_loop.is_finished:
|
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)
|
self.cloud_resize_loop.restart()
|
||||||
if self.fade_out is not None:
|
self.box_manager.update(get_current_ms())
|
||||||
self.fade_out.update(get_current_ms())
|
if self.box_manager.is_finished():
|
||||||
if self.fade_out.is_finished:
|
return self.on_screen_end(self.box_manager.selected_box())
|
||||||
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()
|
return self.handle_input()
|
||||||
|
|
||||||
def draw_background(self):
|
def draw_background(self):
|
||||||
bg_texture = self.textures['entry'][368]
|
tex.draw_texture('background', 'bg')
|
||||||
src = ray.Rectangle(0, 0, bg_texture.width, bg_texture.height)
|
tex.draw_texture('background', 'tower')
|
||||||
dest = ray.Rectangle(0, 0, self.width, bg_texture.height)
|
tex.draw_texture('background', 'shops_center')
|
||||||
ray.draw_texture_pro(bg_texture, src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
|
tex.draw_texture('background', 'people')
|
||||||
|
tex.draw_texture('background', 'shops_left')
|
||||||
ray.draw_texture(self.textures['entry'][369], (self.width // 2) - (self.textures['entry'][369].width // 2), (self.height // 2) - self.textures['entry'][369].height, ray.WHITE)
|
tex.draw_texture('background', 'shops_right')
|
||||||
ray.draw_texture(self.textures['entry'][370], 0, (self.height // 2) - (self.textures['entry'][370].height // 2), ray.WHITE)
|
tex.draw_texture('background', 'lights', scale=2.0, color=ray.fade(ray.WHITE, self.bg_flicker.attribute))
|
||||||
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, self.bg_flicker.attribute))
|
|
||||||
|
|
||||||
def draw_footer(self):
|
def draw_footer(self):
|
||||||
ray.draw_texture(self.textures['entry'][375], 1, self.height - self.textures['entry'][375].height + 7, ray.WHITE)
|
tex.draw_texture('side_select', 'footer')
|
||||||
if self.state == State.SELECT_SIDE or self.side != 0:
|
if self.state == State.SELECT_SIDE or self.side != 0:
|
||||||
ray.draw_texture(self.textures['entry'][376], 1, self.height - self.textures['entry'][376].height + 1, ray.WHITE)
|
tex.draw_texture('side_select', 'footer_left')
|
||||||
if self.state == State.SELECT_SIDE or self.side != 2:
|
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)
|
tex.draw_texture('side_select', 'footer_right')
|
||||||
|
|
||||||
def draw_side_select(self, fade):
|
def draw_side_select(self, fade):
|
||||||
color = ray.fade(ray.WHITE, fade)
|
color = ray.fade(ray.WHITE, fade)
|
||||||
left_x, top_y, right_x, bottom_y = 238, 108, 979, 520
|
tex.draw_texture('side_select', 'box_top_left', color=color)
|
||||||
ray.draw_texture(self.textures['entry'][205], left_x, top_y, color)
|
tex.draw_texture('side_select', 'box_top_right', color=color)
|
||||||
ray.draw_texture(self.textures['entry'][208], right_x, top_y, color)
|
tex.draw_texture('side_select', 'box_bottom_left', color=color)
|
||||||
ray.draw_texture(self.textures['entry'][204], left_x, bottom_y, color)
|
tex.draw_texture('side_select', 'box_bottom_right', color=color)
|
||||||
ray.draw_texture(self.textures['entry'][207], right_x, bottom_y, color)
|
|
||||||
|
|
||||||
texture = self.textures['entry'][209]
|
tex.draw_texture('side_select', 'box_top', color=color)
|
||||||
src = ray.Rectangle(0, 0, texture.width, texture.height)
|
tex.draw_texture('side_select', 'box_bottom', color=color)
|
||||||
dest = ray.Rectangle(left_x + self.textures['entry'][205].width, top_y, right_x - left_x - (self.textures['entry'][205].width), texture.height)
|
tex.draw_texture('side_select', 'box_left', color=color)
|
||||||
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)
|
tex.draw_texture('side_select', 'box_right', color=color)
|
||||||
texture = self.textures['entry'][210]
|
tex.draw_texture('side_select', 'box_center', color=color)
|
||||||
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, color)
|
|
||||||
|
|
||||||
texture = self.textures['entry'][203]
|
tex.draw_texture('side_select', 'question', color=color)
|
||||||
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, 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, color)
|
|
||||||
|
|
||||||
texture = self.textures['entry'][202]
|
tex.draw_texture('side_select', '1P', color=color)
|
||||||
src = ray.Rectangle(0, 0, texture.width, texture.height)
|
tex.draw_texture('side_select', 'cancel', color=color)
|
||||||
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))
|
tex.draw_texture('side_select', '2P', color=color)
|
||||||
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)
|
|
||||||
|
|
||||||
ray.draw_texture(self.textures['entry'][226], 384, 144, color)
|
|
||||||
|
|
||||||
cursor_x = 261
|
|
||||||
cursor_texture = self.textures['entry'][230]
|
|
||||||
flip = 1
|
|
||||||
if self.side == 0:
|
if self.side == 0:
|
||||||
texture = self.textures['entry'][229]
|
tex.draw_texture('side_select', '1P_highlight', color=color)
|
||||||
flip = -1
|
tex.textures['side_select']['1P2P_outline'].x = 261
|
||||||
|
tex.draw_texture('side_select', '1P2P_outline', color=color, mirror='horizontal')
|
||||||
|
elif self.side == 1:
|
||||||
|
tex.draw_texture('side_select', 'cancel_highlight', color=color)
|
||||||
|
tex.draw_texture('side_select', 'cancel_outline', color=color)
|
||||||
else:
|
else:
|
||||||
texture = self.textures['entry'][232]
|
tex.draw_texture('side_select', '2P_highlight', color=color)
|
||||||
ray.draw_texture(texture, 261, 400, color)
|
tex.textures['side_select']['1P2P_outline'].x = 762
|
||||||
|
tex.draw_texture('side_select', '1P2P_outline', color=color)
|
||||||
if self.side == 1:
|
tex.draw_texture('side_select', 'cancel_text', color=color)
|
||||||
texture = self.textures['entry'][76]
|
|
||||||
cursor_texture = self.textures['entry'][77]
|
|
||||||
cursor_x = 512
|
|
||||||
else:
|
|
||||||
texture = self.textures['entry'][228]
|
|
||||||
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, 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, color)
|
|
||||||
|
|
||||||
def draw_player_drum(self):
|
def draw_player_drum(self):
|
||||||
move_x = 0
|
move_x = self.drum_move_3.attribute
|
||||||
if self.drum_move_3 is not None:
|
move_y = self.drum_move_1.attribute + self.drum_move_2.attribute
|
||||||
move_x = int(self.drum_move_3.attribute)
|
tex.update_attr('side_select', 'red_drum', 'x', move_x)
|
||||||
|
tex.update_attr('side_select', 'red_drum', 'y', move_y)
|
||||||
|
tex.update_attr('side_select', 'blue_drum', 'y', move_y)
|
||||||
if self.side == 0:
|
if self.side == 0:
|
||||||
drum_texture = self.textures['entry'][366]
|
tex.draw_texture('side_select', 'red_drum')
|
||||||
x = 160
|
|
||||||
else:
|
else:
|
||||||
drum_texture = self.textures['entry'][367]
|
move_x *= -1
|
||||||
x = 780
|
tex.textures['side_select']['cloud'].init_vals['x'] = tex.textures['side_select']['blue_drum'].init_vals['x']
|
||||||
move_x = move_x * -1
|
tex.update_attr('side_select', 'blue_drum', 'x', move_x)
|
||||||
move_y = 0
|
tex.draw_texture('side_select', 'blue_drum')
|
||||||
if self.drum_move_1 is not None:
|
|
||||||
move_y = int(self.drum_move_1.attribute)
|
|
||||||
if self.drum_move_2 is not None:
|
|
||||||
move_y += int(self.drum_move_2.attribute)
|
|
||||||
ray.draw_texture(drum_texture, x + move_x, 720 + move_y, ray.WHITE)
|
|
||||||
if self.cloud_resize is not None and not self.cloud_resize.is_finished:
|
|
||||||
scale = self.cloud_resize.attribute
|
scale = self.cloud_resize.attribute
|
||||||
else:
|
if self.cloud_resize.is_finished:
|
||||||
scale = max(1, self.cloud_resize_loop.attribute)
|
scale = max(1, self.cloud_resize_loop.attribute)
|
||||||
texture_index = 45
|
|
||||||
if self.cloud_texture_change is not None and self.cloud_texture_change.attribute != 0:
|
|
||||||
texture_index = self.cloud_texture_change.attribute
|
|
||||||
color = ray.fade(ray.WHITE, 1.0)
|
|
||||||
if self.cloud_fade is not None:
|
|
||||||
color = ray.fade(ray.WHITE, self.cloud_fade.attribute)
|
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)
|
tex.update_attr('side_select', 'cloud', 'x', move_x)
|
||||||
|
tex.update_attr('side_select', 'cloud', 'y', move_y)
|
||||||
|
tex.draw_texture('side_select', 'cloud', frame=self.cloud_texture_change.attribute, color=color, scale=scale, center=True)
|
||||||
|
|
||||||
def draw_mode_select(self, fade):
|
def draw_mode_select(self):
|
||||||
self.draw_player_drum()
|
self.draw_player_drum()
|
||||||
color = ray.fade(ray.WHITE, fade)
|
if not self.cloud_texture_change.is_finished:
|
||||||
if self.cloud_fade is not None and self.cloud_fade.is_finished:
|
return
|
||||||
box_width = self.textures['entry'][262].width
|
self.box_manager.draw()
|
||||||
spacing = 80
|
|
||||||
push_distance = 50
|
|
||||||
total_width = self.num_boxes * box_width + (self.num_boxes - 1) * spacing
|
|
||||||
start_x = self.width//2 - total_width//2
|
|
||||||
y = self.height//2 - (self.textures['entry'][262].height//2) - 15
|
|
||||||
for i in range(self.num_boxes):
|
|
||||||
x_pos = start_x + i * (box_width + spacing)
|
|
||||||
push_offset = 0
|
|
||||||
if i != self.selected_box:
|
|
||||||
if i < self.selected_box:
|
|
||||||
push_offset = -push_distance
|
|
||||||
else:
|
|
||||||
push_offset = push_distance
|
|
||||||
final_x = x_pos + push_offset
|
|
||||||
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, 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, 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 + 25, y + 20, box_title.texture.width, box_title.texture.height)
|
|
||||||
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 + 20, y + 20, box_title.texture.width, box_title.texture.height)
|
|
||||||
box_title.draw(src, dest, ray.Vector2(0, 0), 0, color)
|
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
self.draw_background()
|
self.draw_background()
|
||||||
if self.state == State.SELECT_SIDE:
|
if self.state == State.SELECT_SIDE:
|
||||||
self.draw_side_select(self.side_select_fade.attribute)
|
self.draw_side_select(self.side_select_fade.attribute)
|
||||||
elif self.state == State.SELECT_MODE:
|
elif self.state == State.SELECT_MODE:
|
||||||
if self.fade_out is not None:
|
self.draw_mode_select()
|
||||||
self.draw_mode_select(self.fade_out.attribute)
|
|
||||||
else:
|
|
||||||
self.draw_mode_select(1.0)
|
|
||||||
self.draw_footer()
|
self.draw_footer()
|
||||||
|
|
||||||
ray.draw_texture(self.textures['entry'][320], 0, 0, ray.WHITE)
|
tex.draw_texture('global', 'player_entry')
|
||||||
|
|
||||||
if self.fade_out is not None and self.fade_out.is_finished:
|
if self.box_manager.is_finished():
|
||||||
src = ray.Rectangle(0, 0, self.texture_black.width, self.texture_black.height)
|
ray.draw_rectangle(0, 0, self.width, self.height, ray.BLACK)
|
||||||
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)
|
|
||||||
|
|
||||||
def draw_3d(self):
|
def draw_3d(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class Box:
|
||||||
|
def __init__(self, text: tuple[OutlinedText, OutlinedText], location: str):
|
||||||
|
self.text, self.text_highlight = text
|
||||||
|
self.location = location
|
||||||
|
self.box_tex_obj = tex.textures['mode_select']['box']
|
||||||
|
if isinstance(self.box_tex_obj.texture, list):
|
||||||
|
raise Exception("Box texture cannot be iterable")
|
||||||
|
self.texture = self.box_tex_obj.texture
|
||||||
|
self.x = self.box_tex_obj.x
|
||||||
|
self.y = self.box_tex_obj.y
|
||||||
|
self.move = tex.get_animation(10)
|
||||||
|
self.open = tex.get_animation(11)
|
||||||
|
self.is_selected = False
|
||||||
|
self.moving_left = False
|
||||||
|
self.moving_right = False
|
||||||
|
|
||||||
|
def set_positions(self, x: int):
|
||||||
|
self.x = x
|
||||||
|
self.static_x = self.x
|
||||||
|
self.left_x = self.x
|
||||||
|
self.static_left = self.left_x
|
||||||
|
self.right_x = self.left_x + tex.textures['mode_select']['box'].width - tex.textures['mode_select']['box_highlight_right'].width
|
||||||
|
self.static_right = self.right_x
|
||||||
|
|
||||||
|
def update(self, current_time_ms: float, is_selected: bool):
|
||||||
|
self.move.update(current_time_ms)
|
||||||
|
if self.moving_left:
|
||||||
|
self.x = self.static_x - int(self.move.attribute)
|
||||||
|
elif self.moving_right:
|
||||||
|
self.x = self.static_x + int(self.move.attribute)
|
||||||
|
if self.move.is_finished:
|
||||||
|
self.moving_left = False
|
||||||
|
self.moving_right = False
|
||||||
|
self.static_x = self.x
|
||||||
|
|
||||||
|
if is_selected and not self.is_selected:
|
||||||
|
self.open.start()
|
||||||
|
self.is_selected = is_selected
|
||||||
|
if self.is_selected:
|
||||||
|
self.left_x = self.static_left - int(self.open.attribute)
|
||||||
|
self.right_x = self.static_right + int(self.open.attribute)
|
||||||
|
self.open.update(current_time_ms)
|
||||||
|
|
||||||
|
def move_left(self):
|
||||||
|
if not self.move.is_started:
|
||||||
|
self.move.start()
|
||||||
|
self.moving_left = True
|
||||||
|
|
||||||
|
def move_right(self):
|
||||||
|
if not self.move.is_started:
|
||||||
|
self.move.start()
|
||||||
|
self.moving_right = True
|
||||||
|
|
||||||
|
def _draw_highlighted(self, color):
|
||||||
|
texture_left = tex.textures['mode_select']['box_highlight_left'].texture
|
||||||
|
texture_center = tex.textures['mode_select']['box_highlight_center'].texture
|
||||||
|
texture_right = tex.textures['mode_select']['box_highlight_right'].texture
|
||||||
|
if isinstance(texture_center, list) or isinstance(texture_left, list):
|
||||||
|
raise Exception("highlight textures cannot be iterable")
|
||||||
|
center_src = ray.Rectangle(0, 0, texture_center.width, texture_center.height)
|
||||||
|
center_dest = ray.Rectangle(self.left_x + texture_left.width, self.y, self.right_x - self.left_x, texture_center.height)
|
||||||
|
ray.draw_texture_pro(texture_center, center_src, center_dest, ray.Vector2(0, 0), 0, color)
|
||||||
|
ray.draw_texture(texture_center, self.left_x, self.y, color)
|
||||||
|
ray.draw_texture(texture_left, self.left_x, self.y, color)
|
||||||
|
ray.draw_texture(texture_right, self.right_x, self.y, color)
|
||||||
|
|
||||||
|
def _draw_text(self, color):
|
||||||
|
text_x = self.x + (self.texture.width//2) - (self.text.texture.width//2)
|
||||||
|
text_y = self.y + 20
|
||||||
|
text_dest = ray.Rectangle(text_x, text_y, self.text.texture.width, self.text.texture.height)
|
||||||
|
if self.is_selected:
|
||||||
|
self.text_highlight.draw(self.text.default_src, text_dest, ray.Vector2(0, 0), 0, color)
|
||||||
|
else:
|
||||||
|
self.text.draw(self.text.default_src, text_dest, ray.Vector2(0, 0), 0, color)
|
||||||
|
|
||||||
|
def draw(self, fade: float):
|
||||||
|
color = ray.fade(ray.WHITE, fade)
|
||||||
|
ray.draw_texture(self.texture, self.x, self.y, color)
|
||||||
|
if self.is_selected and self.move.is_finished:
|
||||||
|
self._draw_highlighted(color)
|
||||||
|
self._draw_text(color)
|
||||||
|
|
||||||
|
class BoxManager:
|
||||||
|
def __init__(self):
|
||||||
|
self.box_titles: list[tuple[OutlinedText, OutlinedText]] = [
|
||||||
|
(OutlinedText('演奏ゲーム', 50, ray.WHITE, ray.Color(109, 68, 24, 255), outline_thickness=5, vertical=True),
|
||||||
|
OutlinedText('演奏ゲーム', 50, ray.WHITE, ray.BLACK, outline_thickness=5, vertical=True)),
|
||||||
|
(OutlinedText('ゲーム設定', 50, ray.WHITE, ray.Color(109, 68, 24, 255), outline_thickness=5, vertical=True),
|
||||||
|
OutlinedText('ゲーム設定', 50, ray.WHITE, ray.BLACK, outline_thickness=5, vertical=True))]
|
||||||
|
self.box_locations = ["SONG_SELECT", "SETTINGS"]
|
||||||
|
self.num_boxes = len(self.box_titles)
|
||||||
|
self.boxes = [Box(self.box_titles[i], self.box_locations[i]) for i in range(len(self.box_titles))]
|
||||||
|
self.selected_box_index = 0
|
||||||
|
self.fade_out = tex.get_animation(9)
|
||||||
|
|
||||||
|
spacing = 80
|
||||||
|
box_width = self.boxes[0].texture.width
|
||||||
|
total_width = self.num_boxes * box_width + (self.num_boxes - 1) * spacing
|
||||||
|
start_x = 640 - total_width//2
|
||||||
|
for i, box in enumerate(self.boxes):
|
||||||
|
box.set_positions(start_x + i * (box_width + spacing))
|
||||||
|
if i > 0:
|
||||||
|
box.move_right()
|
||||||
|
|
||||||
|
def select_box(self):
|
||||||
|
self.fade_out.start()
|
||||||
|
|
||||||
|
def is_box_selected(self):
|
||||||
|
return self.fade_out.is_started
|
||||||
|
|
||||||
|
def is_finished(self):
|
||||||
|
return self.fade_out.is_finished
|
||||||
|
|
||||||
|
def selected_box(self):
|
||||||
|
return self.boxes[self.selected_box_index].location
|
||||||
|
|
||||||
|
def move_left(self):
|
||||||
|
prev_selection = self.selected_box_index
|
||||||
|
if self.boxes[prev_selection].move.is_started and not self.boxes[prev_selection].move.is_finished:
|
||||||
|
return
|
||||||
|
self.selected_box_index = max(0, self.selected_box_index - 1)
|
||||||
|
if prev_selection == self.selected_box_index:
|
||||||
|
return
|
||||||
|
if self.selected_box_index != self.selected_box_index - 1:
|
||||||
|
self.boxes[self.selected_box_index+1].move_right()
|
||||||
|
self.boxes[self.selected_box_index].move_right()
|
||||||
|
|
||||||
|
def move_right(self):
|
||||||
|
prev_selection = self.selected_box_index
|
||||||
|
if self.boxes[prev_selection].move.is_started and not self.boxes[prev_selection].move.is_finished:
|
||||||
|
return
|
||||||
|
self.selected_box_index = min(self.num_boxes - 1, self.selected_box_index + 1)
|
||||||
|
if prev_selection == self.selected_box_index:
|
||||||
|
return
|
||||||
|
if self.selected_box_index != 0:
|
||||||
|
self.boxes[self.selected_box_index-1].move_left()
|
||||||
|
self.boxes[self.selected_box_index].move_left()
|
||||||
|
|
||||||
|
def update(self, current_time_ms: float):
|
||||||
|
self.fade_out.update(current_time_ms)
|
||||||
|
for i, box in enumerate(self.boxes):
|
||||||
|
is_selected = i == self.selected_box_index
|
||||||
|
box.update(current_time_ms, is_selected)
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
for box in self.boxes:
|
||||||
|
box.draw(self.fade_out.attribute)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from libs.animation import Animation
|
|||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.backgrounds import Background
|
from libs.backgrounds import Background
|
||||||
from libs.tja import Balloon, Drumroll, Note, TJAParser, calculate_base_score
|
from libs.tja import Balloon, Drumroll, Note, TJAParser, calculate_base_score
|
||||||
|
from libs.transition import Transition
|
||||||
from libs.utils import (
|
from libs.utils import (
|
||||||
OutlinedText,
|
OutlinedText,
|
||||||
get_current_ms,
|
get_current_ms,
|
||||||
@@ -138,7 +139,9 @@ class GameScreen:
|
|||||||
subtitle = self.tja.metadata.subtitle.get(global_data.config['general']['language'].lower(), '')
|
subtitle = self.tja.metadata.subtitle.get(global_data.config['general']['language'].lower(), '')
|
||||||
else:
|
else:
|
||||||
subtitle = ''
|
subtitle = ''
|
||||||
self.transition = Transition(self.height, session_data.song_title, subtitle)
|
self.transition = Transition(session_data.song_title, subtitle)
|
||||||
|
self.transition.is_second = True
|
||||||
|
self.transition.start()
|
||||||
|
|
||||||
def on_screen_end(self, next_screen):
|
def on_screen_end(self, next_screen):
|
||||||
self.screen_init = False
|
self.screen_init = False
|
||||||
@@ -236,7 +239,7 @@ class GameScreen:
|
|||||||
if self.song_info is not None:
|
if self.song_info is not None:
|
||||||
self.song_info.draw(self)
|
self.song_info.draw(self)
|
||||||
if self.transition is not None:
|
if self.transition is not None:
|
||||||
self.transition.draw(self.height)
|
self.transition.draw()
|
||||||
if self.result_transition is not None:
|
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])
|
self.result_transition.draw(self.width, self.height, global_data.textures['shutter'][0], global_data.textures['shutter'][1])
|
||||||
|
|
||||||
@@ -764,9 +767,13 @@ class Judgement:
|
|||||||
self.curr_hit_ms = str(round(ms_display, 2))
|
self.curr_hit_ms = str(round(ms_display, 2))
|
||||||
|
|
||||||
self.fade_animation_1 = Animation.create_fade(132, initial_opacity=0.5, delay=100)
|
self.fade_animation_1 = Animation.create_fade(132, initial_opacity=0.5, delay=100)
|
||||||
|
self.fade_animation_1.start()
|
||||||
self.fade_animation_2 = Animation.create_fade(316 - 233.3, delay=233.3)
|
self.fade_animation_2 = Animation.create_fade(316 - 233.3, delay=233.3)
|
||||||
|
self.fade_animation_2.start()
|
||||||
self.move_animation = Animation.create_move(83, total_distance=15, start_position=144)
|
self.move_animation = Animation.create_move(83, total_distance=15, start_position=144)
|
||||||
|
self.move_animation.start()
|
||||||
self.texture_animation = Animation.create_texture_change(100, textures=[(33, 50, 1), (50, 83, 2), (83, 100, 3), (100, float('inf'), 4)])
|
self.texture_animation = Animation.create_texture_change(100, textures=[(33, 50, 1), (50, 83, 2), (83, 100, 3), (100, float('inf'), 4)])
|
||||||
|
self.texture_animation.start()
|
||||||
|
|
||||||
def update(self, current_ms):
|
def update(self, current_ms):
|
||||||
self.fade_animation_1.update(current_ms)
|
self.fade_animation_1.update(current_ms)
|
||||||
@@ -811,6 +818,7 @@ class LaneHitEffect:
|
|||||||
self.type = type
|
self.type = type
|
||||||
self.color = ray.fade(ray.WHITE, 0.5)
|
self.color = ray.fade(ray.WHITE, 0.5)
|
||||||
self.fade = Animation.create_fade(150, delay=83, initial_opacity=0.5)
|
self.fade = Animation.create_fade(150, delay=83, initial_opacity=0.5)
|
||||||
|
self.fade.start()
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
|
|
||||||
def update(self, current_ms: float):
|
def update(self, current_ms: float):
|
||||||
@@ -835,6 +843,7 @@ class DrumHitEffect:
|
|||||||
self.color = ray.fade(ray.WHITE, 1)
|
self.color = ray.fade(ray.WHITE, 1)
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
self.fade = Animation.create_fade(100, delay=67)
|
self.fade = Animation.create_fade(100, delay=67)
|
||||||
|
self.fade.start()
|
||||||
|
|
||||||
def update(self, current_ms: float):
|
def update(self, current_ms: float):
|
||||||
self.fade.update(current_ms)
|
self.fade.update(current_ms)
|
||||||
@@ -861,10 +870,15 @@ class GaugeHitEffect:
|
|||||||
self.note_texture = note_texture
|
self.note_texture = note_texture
|
||||||
self.is_big = big
|
self.is_big = big
|
||||||
self.texture_change = Animation.create_texture_change(116.67, textures=[(0, 33.33, 1), (33.33, 66.66, 2), (66.66, float('inf'), 3)])
|
self.texture_change = Animation.create_texture_change(116.67, textures=[(0, 33.33, 1), (33.33, 66.66, 2), (66.66, float('inf'), 3)])
|
||||||
|
self.texture_change.start()
|
||||||
self.circle_fadein = Animation.create_fade(133, initial_opacity=0.0, final_opacity=1.0, delay=16.67)
|
self.circle_fadein = Animation.create_fade(133, initial_opacity=0.0, final_opacity=1.0, delay=16.67)
|
||||||
|
self.circle_fadein.start()
|
||||||
self.resize = Animation.create_texture_resize(233, delay=self.texture_change.duration, initial_size=0.75, final_size=1.15)
|
self.resize = Animation.create_texture_resize(233, delay=self.texture_change.duration, initial_size=0.75, final_size=1.15)
|
||||||
|
self.resize.start()
|
||||||
self.fade_out = Animation.create_fade(66, delay=233)
|
self.fade_out = Animation.create_fade(66, delay=233)
|
||||||
|
self.fade_out.start()
|
||||||
self.test = Animation.create_fade(300, delay=116.67, initial_opacity=0.0, final_opacity=1.0)
|
self.test = Animation.create_fade(300, delay=116.67, initial_opacity=0.0, final_opacity=1.0)
|
||||||
|
self.test.start()
|
||||||
self.color = ray.fade(ray.YELLOW, self.circle_fadein.attribute)
|
self.color = ray.fade(ray.YELLOW, self.circle_fadein.attribute)
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
def update(self, current_ms):
|
def update(self, current_ms):
|
||||||
@@ -1000,7 +1014,9 @@ class DrumrollCounter:
|
|||||||
self.total_duration = 1349
|
self.total_duration = 1349
|
||||||
self.drumroll_count = 0
|
self.drumroll_count = 0
|
||||||
self.fade_animation = Animation.create_fade(166, delay=self.total_duration - 166)
|
self.fade_animation = Animation.create_fade(166, delay=self.total_duration - 166)
|
||||||
|
self.fade_animation.start()
|
||||||
self.stretch_animation = Animation.create_text_stretch(0)
|
self.stretch_animation = Animation.create_text_stretch(0)
|
||||||
|
self.stretch_animation.start()
|
||||||
|
|
||||||
def update_count(self, count: int, elapsed_time: float):
|
def update_count(self, count: int, elapsed_time: float):
|
||||||
self.total_duration = elapsed_time + 1349
|
self.total_duration = elapsed_time + 1349
|
||||||
@@ -1008,6 +1024,7 @@ class DrumrollCounter:
|
|||||||
if self.drumroll_count != count:
|
if self.drumroll_count != count:
|
||||||
self.drumroll_count = count
|
self.drumroll_count = count
|
||||||
self.stretch_animation = Animation.create_text_stretch(50)
|
self.stretch_animation = Animation.create_text_stretch(50)
|
||||||
|
self.stretch_animation.start()
|
||||||
|
|
||||||
def update(self, game_screen: GameScreen, current_ms: float, drumroll_count: int):
|
def update(self, game_screen: GameScreen, current_ms: float, drumroll_count: int):
|
||||||
self.stretch_animation.update(current_ms)
|
self.stretch_animation.update(current_ms)
|
||||||
@@ -1040,12 +1057,15 @@ class BalloonAnimation:
|
|||||||
self.balloon_total = balloon_total
|
self.balloon_total = balloon_total
|
||||||
self.is_popped = False
|
self.is_popped = False
|
||||||
self.fade_animation = Animation.create_fade(166)
|
self.fade_animation = Animation.create_fade(166)
|
||||||
|
self.fade_animation.start()
|
||||||
self.stretch_animation = Animation.create_text_stretch(0)
|
self.stretch_animation = Animation.create_text_stretch(0)
|
||||||
|
self.stretch_animation.start()
|
||||||
|
|
||||||
def update_count(self, balloon_count: int):
|
def update_count(self, balloon_count: int):
|
||||||
if self.balloon_count != balloon_count:
|
if self.balloon_count != balloon_count:
|
||||||
self.balloon_count = balloon_count
|
self.balloon_count = balloon_count
|
||||||
self.stretch_animation = Animation.create_text_stretch(50)
|
self.stretch_animation = Animation.create_text_stretch(50)
|
||||||
|
self.stretch_animation.start()
|
||||||
|
|
||||||
def update(self, game_screen: GameScreen, current_ms: float, balloon_count: int, is_popped: bool):
|
def update(self, game_screen: GameScreen, current_ms: float, balloon_count: int, is_popped: bool):
|
||||||
self.update_count(balloon_count)
|
self.update_count(balloon_count)
|
||||||
@@ -1084,6 +1104,7 @@ class Combo:
|
|||||||
def __init__(self, combo: int, current_ms: float):
|
def __init__(self, combo: int, current_ms: float):
|
||||||
self.combo = combo
|
self.combo = combo
|
||||||
self.stretch_animation = Animation.create_text_stretch(0)
|
self.stretch_animation = Animation.create_text_stretch(0)
|
||||||
|
self.stretch_animation.start()
|
||||||
self.color = [ray.fade(ray.WHITE, 1), ray.fade(ray.WHITE, 1), ray.fade(ray.WHITE, 1)]
|
self.color = [ray.fade(ray.WHITE, 1), ray.fade(ray.WHITE, 1), ray.fade(ray.WHITE, 1)]
|
||||||
self.glimmer_dict = {0: 0, 1: 0, 2: 0}
|
self.glimmer_dict = {0: 0, 1: 0, 2: 0}
|
||||||
self.total_time = 250
|
self.total_time = 250
|
||||||
@@ -1098,6 +1119,7 @@ class Combo:
|
|||||||
if self.combo != combo:
|
if self.combo != combo:
|
||||||
self.combo = combo
|
self.combo = combo
|
||||||
self.stretch_animation = Animation.create_text_stretch(50)
|
self.stretch_animation = Animation.create_text_stretch(50)
|
||||||
|
self.stretch_animation.start()
|
||||||
|
|
||||||
def update(self, game_screen: GameScreen, current_ms: float, combo: int):
|
def update(self, game_screen: GameScreen, current_ms: float, combo: int):
|
||||||
self.update_count(current_ms, combo)
|
self.update_count(current_ms, combo)
|
||||||
@@ -1149,11 +1171,13 @@ class ScoreCounter:
|
|||||||
def __init__(self, score: int):
|
def __init__(self, score: int):
|
||||||
self.score = score
|
self.score = score
|
||||||
self.stretch_animation = Animation.create_text_stretch(0)
|
self.stretch_animation = Animation.create_text_stretch(0)
|
||||||
|
self.stretch_animation.start()
|
||||||
|
|
||||||
def update_count(self, current_ms: float, score: int):
|
def update_count(self, current_ms: float, score: int):
|
||||||
if self.score != score:
|
if self.score != score:
|
||||||
self.score = score
|
self.score = score
|
||||||
self.stretch_animation = Animation.create_text_stretch(50)
|
self.stretch_animation = Animation.create_text_stretch(50)
|
||||||
|
self.stretch_animation.start()
|
||||||
|
|
||||||
def update(self, current_ms: float, score: int):
|
def update(self, current_ms: float, score: int):
|
||||||
self.update_count(current_ms, score)
|
self.update_count(current_ms, score)
|
||||||
@@ -1175,11 +1199,17 @@ class ScoreCounterAnimation:
|
|||||||
def __init__(self, counter: int):
|
def __init__(self, counter: int):
|
||||||
self.counter = counter
|
self.counter = counter
|
||||||
self.fade_animation_1 = Animation.create_fade(50, initial_opacity=0.0, final_opacity=1.0)
|
self.fade_animation_1 = Animation.create_fade(50, initial_opacity=0.0, final_opacity=1.0)
|
||||||
|
self.fade_animation_1.start()
|
||||||
self.move_animation_1 = Animation.create_move(80, total_distance=-20, start_position=175)
|
self.move_animation_1 = Animation.create_move(80, total_distance=-20, start_position=175)
|
||||||
|
self.move_animation_1.start()
|
||||||
self.fade_animation_2 = Animation.create_fade(80, delay=366.74)
|
self.fade_animation_2 = Animation.create_fade(80, delay=366.74)
|
||||||
|
self.fade_animation_2.start()
|
||||||
self.move_animation_2 = Animation.create_move(66, total_distance=5, start_position=145, delay=80)
|
self.move_animation_2 = Animation.create_move(66, total_distance=5, start_position=145, delay=80)
|
||||||
|
self.move_animation_2.start()
|
||||||
self.move_animation_3 = Animation.create_move(66, delay=279.36, total_distance=-2, start_position=146)
|
self.move_animation_3 = Animation.create_move(66, delay=279.36, total_distance=-2, start_position=146)
|
||||||
|
self.move_animation_3.start()
|
||||||
self.move_animation_4 = Animation.create_move(80, delay=366.74, total_distance=10, start_position=148)
|
self.move_animation_4 = Animation.create_move(80, delay=366.74, total_distance=10, start_position=148)
|
||||||
|
self.move_animation_4.start()
|
||||||
|
|
||||||
self.color = ray.fade(ray.Color(254, 102, 0, 255), 1.0)
|
self.color = ray.fade(ray.Color(254, 102, 0, 255), 1.0)
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
@@ -1236,8 +1266,11 @@ class SongInfo:
|
|||||||
song_name, 40, ray.Color(255, 255, 255, 255), ray.Color(0, 0, 0, 255), outline_thickness=5
|
song_name, 40, ray.Color(255, 255, 255, 255), ray.Color(0, 0, 0, 255), outline_thickness=5
|
||||||
)
|
)
|
||||||
self.fade_in = Animation.create_fade(self.FADE_DURATION, initial_opacity=0.0, final_opacity=1.0)
|
self.fade_in = Animation.create_fade(self.FADE_DURATION, initial_opacity=0.0, final_opacity=1.0)
|
||||||
|
self.fade_in.start()
|
||||||
self.fade_out = Animation.create_fade(self.FADE_DURATION, delay=self.DISPLAY_DURATION)
|
self.fade_out = Animation.create_fade(self.FADE_DURATION, delay=self.DISPLAY_DURATION)
|
||||||
|
self.fade_out.start()
|
||||||
self.fade_fake = Animation.create_fade(0, delay=self.DISPLAY_DURATION*2 + self.FADE_DURATION)
|
self.fade_fake = Animation.create_fade(0, delay=self.DISPLAY_DURATION*2 + self.FADE_DURATION)
|
||||||
|
self.fade_fake.start()
|
||||||
|
|
||||||
def update(self, current_ms: float):
|
def update(self, current_ms: float):
|
||||||
self.fade_in.update(current_ms)
|
self.fade_in.update(current_ms)
|
||||||
@@ -1256,8 +1289,11 @@ class SongInfo:
|
|||||||
|
|
||||||
def _reset_animations(self, current_ms: float):
|
def _reset_animations(self, current_ms: float):
|
||||||
self.fade_in = Animation.create_fade(self.FADE_DURATION, initial_opacity=0.0, final_opacity=1.0)
|
self.fade_in = Animation.create_fade(self.FADE_DURATION, initial_opacity=0.0, final_opacity=1.0)
|
||||||
|
self.fade_in.start()
|
||||||
self.fade_out = Animation.create_fade(self.FADE_DURATION, delay=self.DISPLAY_DURATION)
|
self.fade_out = Animation.create_fade(self.FADE_DURATION, delay=self.DISPLAY_DURATION)
|
||||||
|
self.fade_out.start()
|
||||||
self.fade_fake = Animation.create_fade(0, delay=self.DISPLAY_DURATION*2 + self.FADE_DURATION)
|
self.fade_fake = Animation.create_fade(0, delay=self.DISPLAY_DURATION*2 + self.FADE_DURATION)
|
||||||
|
self.fade_fake.start()
|
||||||
|
|
||||||
def draw(self, game_screen: GameScreen):
|
def draw(self, game_screen: GameScreen):
|
||||||
song_texture_index = (global_data.songs_played % 4) + 8
|
song_texture_index = (global_data.songs_played % 4) + 8
|
||||||
@@ -1273,62 +1309,10 @@ class SongInfo:
|
|||||||
dest = ray.Rectangle(text_x, text_y, self.song_title.texture.width, self.song_title.texture.height)
|
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)
|
self.song_title.draw(src, dest, ray.Vector2(0, 0), 0, self.song_name_fade)
|
||||||
|
|
||||||
class Transition:
|
|
||||||
def __init__(self, screen_height: int, title: str, subtitle: str) -> None:
|
|
||||||
duration = 266
|
|
||||||
self.is_finished = False
|
|
||||||
self.rainbow_up = Animation.create_move(duration, start_position=0, total_distance=screen_height + global_data.textures['scene_change_rainbow'][2].height, ease_in='cubic')
|
|
||||||
self.chara_down = None
|
|
||||||
self.title = OutlinedText(title, 40, ray.WHITE, ray.BLACK, outline_thickness=5)
|
|
||||||
self.subtitle = OutlinedText(subtitle, 30, ray.WHITE, ray.BLACK, outline_thickness=5)
|
|
||||||
self.song_info_fade = Animation.create_fade(duration/2)
|
|
||||||
def update(self, current_time_ms: float):
|
|
||||||
self.rainbow_up.update(current_time_ms)
|
|
||||||
self.song_info_fade.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_song_info(self):
|
|
||||||
texture = global_data.textures['scene_change_rainbow'][6]
|
|
||||||
y = 720//2 - texture.height
|
|
||||||
src = ray.Rectangle(0, 0, texture.width, texture.height)
|
|
||||||
dest = ray.Rectangle(1280//2 - (texture.width*3)//2, y, texture.width*3, texture.height*2)
|
|
||||||
ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, min(0.70, self.song_info_fade.attribute)))
|
|
||||||
|
|
||||||
texture = self.title.texture
|
|
||||||
y = 720//2 - texture.height//2 - 20
|
|
||||||
src = ray.Rectangle(0, 0, texture.width, texture.height)
|
|
||||||
dest = ray.Rectangle(1280//2 - texture.width//2, y, texture.width, texture.height)
|
|
||||||
self.title.draw(src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, self.song_info_fade.attribute))
|
|
||||||
|
|
||||||
texture = self.subtitle.texture
|
|
||||||
src = ray.Rectangle(0, 0, texture.width, texture.height)
|
|
||||||
dest = ray.Rectangle(1280//2 - texture.width//2, y + 50, texture.width, texture.height)
|
|
||||||
self.subtitle.draw(src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, self.song_info_fade.attribute))
|
|
||||||
|
|
||||||
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(global_data.textures['scene_change_rainbow'][4], 142, 14 -int(self.rainbow_up.attribute*3) - offset, ray.WHITE)
|
|
||||||
ray.draw_texture(global_data.textures['scene_change_rainbow'][5], 958, 144 -int(self.rainbow_up.attribute*3) - offset, ray.WHITE)
|
|
||||||
ray.draw_texture(texture, 76, -int(self.rainbow_up.attribute*3) - offset, ray.WHITE)
|
|
||||||
|
|
||||||
self.draw_song_info()
|
|
||||||
|
|
||||||
class ResultTransition:
|
class ResultTransition:
|
||||||
def __init__(self, screen_height: int):
|
def __init__(self, screen_height: int):
|
||||||
self.move = Animation.create_move(983.33, start_position=0, total_distance=screen_height//2, ease_out='quadratic')
|
self.move = Animation.create_move(983.33, start_position=0, total_distance=screen_height//2, ease_out='quadratic')
|
||||||
|
self.move.start()
|
||||||
|
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
|
|
||||||
@@ -1409,6 +1393,7 @@ class Gauge:
|
|||||||
|
|
||||||
def add_good(self):
|
def add_good(self):
|
||||||
self.gauge_update_anim = Animation.create_fade(450)
|
self.gauge_update_anim = Animation.create_fade(450)
|
||||||
|
self.gauge_update_anim.start()
|
||||||
self.previous_length = int(self.gauge_length)
|
self.previous_length = int(self.gauge_length)
|
||||||
self.gauge_length += (1 / self.total_notes) * (100 * (self.clear_start[self.difficulty] / self.table[self.difficulty][self.level]["clear_rate"]))
|
self.gauge_length += (1 / self.total_notes) * (100 * (self.clear_start[self.difficulty] / self.table[self.difficulty][self.level]["clear_rate"]))
|
||||||
if self.gauge_length > 87:
|
if self.gauge_length > 87:
|
||||||
@@ -1416,6 +1401,7 @@ class Gauge:
|
|||||||
|
|
||||||
def add_ok(self):
|
def add_ok(self):
|
||||||
self.gauge_update_anim = Animation.create_fade(450)
|
self.gauge_update_anim = Animation.create_fade(450)
|
||||||
|
self.gauge_update_anim.start()
|
||||||
self.previous_length = int(self.gauge_length)
|
self.previous_length = int(self.gauge_length)
|
||||||
self.gauge_length += ((1 * self.table[self.difficulty][self.level]["ok_multiplier"]) / self.total_notes) * (100 * (self.clear_start[self.difficulty] / self.table[self.difficulty][self.level]["clear_rate"]))
|
self.gauge_length += ((1 * self.table[self.difficulty][self.level]["ok_multiplier"]) / self.total_notes) * (100 * (self.clear_start[self.difficulty] / self.table[self.difficulty][self.level]["clear_rate"]))
|
||||||
if self.gauge_length > 87:
|
if self.gauge_length > 87:
|
||||||
@@ -1430,6 +1416,7 @@ class Gauge:
|
|||||||
def update(self, current_ms: float, good_count: int, ok_count: int, bad_count: int, total_notes: int):
|
def update(self, current_ms: float, good_count: int, ok_count: int, bad_count: int, total_notes: int):
|
||||||
if self.gauge_length == 87 and self.rainbow_fade_in is None:
|
if self.gauge_length == 87 and self.rainbow_fade_in is None:
|
||||||
self.rainbow_fade_in = Animation.create_fade(450, initial_opacity=0.0, final_opacity=1.0)
|
self.rainbow_fade_in = Animation.create_fade(450, initial_opacity=0.0, final_opacity=1.0)
|
||||||
|
self.rainbow_fade_in.start()
|
||||||
|
|
||||||
if self.gauge_update_anim is not None:
|
if self.gauge_update_anim is not None:
|
||||||
self.gauge_update_anim.update(current_ms)
|
self.gauge_update_anim.update(current_ms)
|
||||||
@@ -1441,6 +1428,7 @@ class Gauge:
|
|||||||
|
|
||||||
if self.rainbow_animation is None:
|
if self.rainbow_animation is None:
|
||||||
self.rainbow_animation = Animation.create_texture_change((16.67*8) * 3, textures=[((16.67 * 3) * i, (16.67 * 3) * (i + 1), i) for i in range(8)])
|
self.rainbow_animation = Animation.create_texture_change((16.67*8) * 3, textures=[((16.67 * 3) * i, (16.67 * 3) * (i + 1), i) for i in range(8)])
|
||||||
|
self.rainbow_animation.start()
|
||||||
else:
|
else:
|
||||||
self.rainbow_animation.update(current_ms)
|
self.rainbow_animation.update(current_ms)
|
||||||
if self.rainbow_animation.is_finished or self.gauge_length < 87:
|
if self.rainbow_animation.is_finished or self.gauge_length < 87:
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import threading
|
import threading
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.song_hash import build_song_hashes
|
from libs.song_hash import build_song_hashes
|
||||||
from libs.utils import get_current_ms, global_data, load_all_textures_from_zip
|
from libs.texture import tex
|
||||||
|
from libs.utils import get_current_ms, global_data
|
||||||
from scenes.song_select import SongSelectScreen
|
from scenes.song_select import SongSelectScreen
|
||||||
|
|
||||||
|
|
||||||
@@ -29,8 +29,6 @@ class LoadScreen:
|
|||||||
self.loading_thread = None
|
self.loading_thread = None
|
||||||
self.navigator_thread = None
|
self.navigator_thread = None
|
||||||
|
|
||||||
self.textures = load_all_textures_from_zip(Path('Graphics/lumendata/attract/kidou.zip'))
|
|
||||||
|
|
||||||
self.fade_in = None
|
self.fade_in = None
|
||||||
|
|
||||||
def _load_song_hashes(self):
|
def _load_song_hashes(self):
|
||||||
@@ -53,6 +51,7 @@ class LoadScreen:
|
|||||||
|
|
||||||
def on_screen_start(self):
|
def on_screen_start(self):
|
||||||
if not self.screen_init:
|
if not self.screen_init:
|
||||||
|
tex.load_screen_textures('loading')
|
||||||
self.loading_thread = threading.Thread(target=self._load_song_hashes)
|
self.loading_thread = threading.Thread(target=self._load_song_hashes)
|
||||||
self.loading_thread.daemon = True
|
self.loading_thread.daemon = True
|
||||||
self.loading_thread.start()
|
self.loading_thread.start()
|
||||||
@@ -60,7 +59,7 @@ class LoadScreen:
|
|||||||
|
|
||||||
def on_screen_end(self, next_screen: str):
|
def on_screen_end(self, next_screen: str):
|
||||||
self.screen_init = False
|
self.screen_init = False
|
||||||
|
tex.unload_textures()
|
||||||
if self.loading_thread and self.loading_thread.is_alive():
|
if self.loading_thread and self.loading_thread.is_alive():
|
||||||
self.loading_thread.join(timeout=1.0)
|
self.loading_thread.join(timeout=1.0)
|
||||||
if self.navigator_thread and self.navigator_thread.is_alive():
|
if self.navigator_thread and self.navigator_thread.is_alive():
|
||||||
@@ -79,6 +78,7 @@ class LoadScreen:
|
|||||||
|
|
||||||
if self.loading_complete and self.fade_in is None:
|
if self.loading_complete and self.fade_in is None:
|
||||||
self.fade_in = Animation.create_fade(1000, initial_opacity=0.0, final_opacity=1.0, ease_in='cubic')
|
self.fade_in = Animation.create_fade(1000, initial_opacity=0.0, final_opacity=1.0, ease_in='cubic')
|
||||||
|
self.fade_in.start()
|
||||||
|
|
||||||
if self.fade_in is not None:
|
if self.fade_in is not None:
|
||||||
self.fade_in.update(get_current_ms())
|
self.fade_in.update(get_current_ms())
|
||||||
@@ -87,7 +87,7 @@ class LoadScreen:
|
|||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
ray.draw_rectangle(0, 0, self.width, self.height, ray.BLACK)
|
ray.draw_rectangle(0, 0, self.width, self.height, ray.BLACK)
|
||||||
ray.draw_texture(self.textures['kidou'][1], self.width//2 - self.textures['kidou'][1].width//2, 50, ray.WHITE)
|
tex.draw_texture('kidou', 'warning')
|
||||||
|
|
||||||
# Draw progress bar background
|
# Draw progress bar background
|
||||||
ray.draw_rectangle(
|
ray.draw_rectangle(
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ class ResultScreen:
|
|||||||
if self.score_delay is not None:
|
if self.score_delay is not None:
|
||||||
if get_current_ms() > self.score_delay and self.fade_in_bottom is None:
|
if get_current_ms() > self.score_delay and self.fade_in_bottom is None:
|
||||||
self.fade_in_bottom = Animation.create_fade(333, initial_opacity=0.0, final_opacity=1.0)
|
self.fade_in_bottom = Animation.create_fade(333, initial_opacity=0.0, final_opacity=1.0)
|
||||||
|
self.fade_in_bottom.start()
|
||||||
if self.gauge is not None:
|
if self.gauge is not None:
|
||||||
self.state = self.gauge.state
|
self.state = self.gauge.state
|
||||||
|
|
||||||
@@ -258,10 +259,15 @@ class Crown:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
duration = 466
|
duration = 466
|
||||||
self.resize = Animation.create_texture_resize(duration, initial_size=3.5, final_size=0.90, ease_in='quadratic')
|
self.resize = Animation.create_texture_resize(duration, initial_size=3.5, final_size=0.90, ease_in='quadratic')
|
||||||
|
self.resize.start()
|
||||||
self.resize_fix = Animation.create_texture_resize(216, initial_size=self.resize.final_size, final_size=1.0, delay=self.resize.duration)
|
self.resize_fix = Animation.create_texture_resize(216, initial_size=self.resize.final_size, final_size=1.0, delay=self.resize.duration)
|
||||||
|
self.resize_fix.start()
|
||||||
self.white_fadein = Animation.create_fade(133, initial_opacity=0.0, final_opacity=1.0, delay=self.resize.duration + self.resize_fix.duration, reverse_delay=0)
|
self.white_fadein = Animation.create_fade(133, initial_opacity=0.0, final_opacity=1.0, delay=self.resize.duration + self.resize_fix.duration, reverse_delay=0)
|
||||||
|
self.white_fadein.start()
|
||||||
self.gleam = Animation.create_texture_change(400, textures=[(0, 200, 0), (200, 250, 127), (250, 300, 128), (300, 350, 129), (350, 400, 0)], delay=self.resize.duration + self.resize_fix.duration + self.white_fadein.duration)
|
self.gleam = Animation.create_texture_change(400, textures=[(0, 200, 0), (200, 250, 127), (250, 300, 128), (300, 350, 129), (350, 400, 0)], delay=self.resize.duration + self.resize_fix.duration + self.white_fadein.duration)
|
||||||
|
self.gleam.start()
|
||||||
self.fadein = Animation.create_fade(duration, initial_opacity=0.0, final_opacity=1.0, ease_in='quadratic')
|
self.fadein = Animation.create_fade(duration, initial_opacity=0.0, final_opacity=1.0, ease_in='quadratic')
|
||||||
|
self.fadein.start()
|
||||||
self.sound = audio.load_sound(Path('Sounds/result/SE_RESULT [1].ogg'))
|
self.sound = audio.load_sound(Path('Sounds/result/SE_RESULT [1].ogg'))
|
||||||
self.sound_played = False
|
self.sound_played = False
|
||||||
|
|
||||||
@@ -303,12 +309,16 @@ class BottomCharacters:
|
|||||||
self.char_1_index = 339
|
self.char_1_index = 339
|
||||||
self.char_2_index = 340
|
self.char_2_index = 340
|
||||||
self.c_bounce_up = Animation.create_move(266, total_distance=40, ease_in='quadratic')
|
self.c_bounce_up = Animation.create_move(266, total_distance=40, ease_in='quadratic')
|
||||||
|
self.c_bounce_up.start()
|
||||||
self.c_bounce_down = Animation.create_move(266, total_distance=40, ease_out='quadratic', delay=self.c_bounce_up.duration)
|
self.c_bounce_down = Animation.create_move(266, total_distance=40, ease_out='quadratic', delay=self.c_bounce_up.duration)
|
||||||
|
self.c_bounce_down.start()
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.move_up = Animation.create_move(366, total_distance=380, ease_out='cubic')
|
self.move_up = Animation.create_move(366, total_distance=380, ease_out='cubic')
|
||||||
|
self.move_up.start()
|
||||||
self.move_down = Animation.create_move(133, total_distance=30, ease_out='cubic', delay=self.move_up.duration-5)
|
self.move_down = Animation.create_move(133, total_distance=30, ease_out='cubic', delay=self.move_up.duration-5)
|
||||||
|
self.move_down.start()
|
||||||
|
|
||||||
def update(self, state):
|
def update(self, state):
|
||||||
self.state = state
|
self.state = state
|
||||||
@@ -317,10 +327,14 @@ class BottomCharacters:
|
|||||||
self.char_2_index = 346
|
self.char_2_index = 346
|
||||||
if self.bounce_up is None:
|
if self.bounce_up is None:
|
||||||
self.bounce_up = Animation.create_move(266, total_distance=40, ease_in='quadratic')
|
self.bounce_up = Animation.create_move(266, total_distance=40, ease_in='quadratic')
|
||||||
|
self.bounce_up.start()
|
||||||
self.bounce_down = Animation.create_move(266, total_distance=40, ease_out='quadratic', delay=self.bounce_up.duration)
|
self.bounce_down = Animation.create_move(266, total_distance=40, ease_out='quadratic', delay=self.bounce_up.duration)
|
||||||
|
self.bounce_down.start()
|
||||||
self.move_center = Animation.create_move(266, total_distance=450, ease_out='quadratic', delay=self.bounce_down.duration+self.bounce_up.duration)
|
self.move_center = Animation.create_move(266, total_distance=450, ease_out='quadratic', delay=self.bounce_down.duration+self.bounce_up.duration)
|
||||||
|
self.move_center.start()
|
||||||
if self.flower_up is None:
|
if self.flower_up is None:
|
||||||
self.flower_up = Animation.create_move(333, total_distance=365, ease_out='quadratic')
|
self.flower_up = Animation.create_move(333, total_distance=365, ease_out='quadratic')
|
||||||
|
self.flower_up.start()
|
||||||
self.flower_start = get_current_ms()
|
self.flower_start = get_current_ms()
|
||||||
elif self.state == State.FAIL:
|
elif self.state == State.FAIL:
|
||||||
self.char_1_index = 347
|
self.char_1_index = 347
|
||||||
@@ -384,6 +398,7 @@ class BottomCharacters:
|
|||||||
class FadeIn:
|
class FadeIn:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.fadein = Animation.create_fade(450, initial_opacity=1.0, final_opacity=0.0, delay=100)
|
self.fadein = Animation.create_fade(450, initial_opacity=1.0, final_opacity=0.0, delay=100)
|
||||||
|
self.fadein.start()
|
||||||
self.fade = ray.fade(ray.WHITE, self.fadein.attribute)
|
self.fade = ray.fade(ray.WHITE, self.fadein.attribute)
|
||||||
|
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
@@ -430,6 +445,7 @@ class Gauge:
|
|||||||
self.gauge_length = gauge_length
|
self.gauge_length = gauge_length
|
||||||
self.rainbow_animation = None
|
self.rainbow_animation = None
|
||||||
self.gauge_fade_in = Animation.create_fade(366, initial_opacity=0.0, final_opacity=1.0)
|
self.gauge_fade_in = Animation.create_fade(366, initial_opacity=0.0, final_opacity=1.0)
|
||||||
|
self.gauge_fade_in.start()
|
||||||
self.is_finished = self.gauge_fade_in.is_finished
|
self.is_finished = self.gauge_fade_in.is_finished
|
||||||
if self.gauge_length == 87:
|
if self.gauge_length == 87:
|
||||||
self.state = State.RAINBOW
|
self.state = State.RAINBOW
|
||||||
@@ -440,10 +456,12 @@ class Gauge:
|
|||||||
|
|
||||||
def _create_rainbow_anim(self, current_ms):
|
def _create_rainbow_anim(self, current_ms):
|
||||||
anim = Animation.create_texture_change((16.67*8) * 3, textures=[((16.67 * 3) * i, (16.67 * 3) * (i + 1), i) for i in range(8)])
|
anim = Animation.create_texture_change((16.67*8) * 3, textures=[((16.67 * 3) * i, (16.67 * 3) * (i + 1), i) for i in range(8)])
|
||||||
|
anim.start()
|
||||||
return anim
|
return anim
|
||||||
|
|
||||||
def _create_anim(self, current_ms: float, init: float, final: float):
|
def _create_anim(self, current_ms: float, init: float, final: float):
|
||||||
anim = Animation.create_fade(450, initial_opacity=init, final_opacity=final)
|
anim = Animation.create_fade(450, initial_opacity=init, final_opacity=final)
|
||||||
|
anim.start()
|
||||||
return anim
|
return anim
|
||||||
|
|
||||||
def update(self, current_ms: float):
|
def update(self, current_ms: float):
|
||||||
@@ -493,6 +511,7 @@ class FadeOut:
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.texture = global_data.textures['scene_change_fade'][0]
|
self.texture = global_data.textures['scene_change_fade'][0]
|
||||||
self.fade_out = Animation.create_fade(1000, initial_opacity=0.0, final_opacity=1.0)
|
self.fade_out = Animation.create_fade(1000, initial_opacity=0.0, final_opacity=1.0)
|
||||||
|
self.fade_out.start()
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
def update(self, current_time_ms: float):
|
def update(self, current_time_ms: float):
|
||||||
self.fade_out.update(current_time_ms)
|
self.fade_out.update(current_time_ms)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
222
scenes/title.py
222
scenes/title.py
@@ -3,15 +3,13 @@ from pathlib import Path
|
|||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.animation import Animation
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
|
from libs.texture import tex
|
||||||
from libs.utils import (
|
from libs.utils import (
|
||||||
get_current_ms,
|
get_current_ms,
|
||||||
global_data,
|
global_data,
|
||||||
is_l_don_pressed,
|
is_l_don_pressed,
|
||||||
is_r_don_pressed,
|
is_r_don_pressed,
|
||||||
load_all_textures_from_zip,
|
|
||||||
load_texture_from_zip,
|
|
||||||
)
|
)
|
||||||
from libs.video import VideoPlayer
|
from libs.video import VideoPlayer
|
||||||
|
|
||||||
@@ -29,9 +27,7 @@ class TitleScreen:
|
|||||||
self.op_video_list = [file for file in video_dir.glob("**/*.mp4")]
|
self.op_video_list = [file for file in video_dir.glob("**/*.mp4")]
|
||||||
video_dir = Path(global_data.config["paths"]["video_path"]) / "attract_videos"
|
video_dir = Path(global_data.config["paths"]["video_path"]) / "attract_videos"
|
||||||
self.attract_video_list = [file for file in video_dir.glob("**/*.mp4")]
|
self.attract_video_list = [file for file in video_dir.glob("**/*.mp4")]
|
||||||
self.load_sounds()
|
|
||||||
self.screen_init = False
|
self.screen_init = False
|
||||||
self.fade_out = None
|
|
||||||
|
|
||||||
def load_sounds(self):
|
def load_sounds(self):
|
||||||
sounds_dir = Path("Sounds")
|
sounds_dir = Path("Sounds")
|
||||||
@@ -41,32 +37,25 @@ class TitleScreen:
|
|||||||
self.sound_bachi_hit = audio.load_sound(title_dir / "SE_ATTRACT_3.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")
|
self.sound_warning_message = audio.load_sound(title_dir / "VO_ATTRACT_3.ogg")
|
||||||
self.sound_warning_error = audio.load_sound(title_dir / "SE_ATTRACT_1.ogg")
|
self.sound_warning_error = audio.load_sound(title_dir / "SE_ATTRACT_1.ogg")
|
||||||
self.sounds = [self.sound_bachi_swipe, self.sound_bachi_hit, self.sound_warning_message, self.sound_warning_error]
|
|
||||||
|
|
||||||
def load_textures(self):
|
|
||||||
self.textures = load_all_textures_from_zip(Path('Graphics/lumendata/attract/keikoku.zip'))
|
|
||||||
self.texture_black = load_texture_from_zip(Path('Graphics/lumendata/attract/movie.zip'), 'movie_img00000.png')
|
|
||||||
|
|
||||||
def on_screen_start(self):
|
def on_screen_start(self):
|
||||||
if not self.screen_init:
|
if not self.screen_init:
|
||||||
self.screen_init = True
|
self.screen_init = True
|
||||||
self.load_textures()
|
tex.load_screen_textures('title')
|
||||||
|
self.load_sounds()
|
||||||
self.state = State.OP_VIDEO
|
self.state = State.OP_VIDEO
|
||||||
self.op_video = None
|
self.op_video = None
|
||||||
self.attract_video = None
|
self.attract_video = None
|
||||||
self.warning_board = None
|
self.warning_board = None
|
||||||
|
self.fade_out = tex.get_animation(13)
|
||||||
|
|
||||||
def on_screen_end(self) -> str:
|
def on_screen_end(self) -> str:
|
||||||
if self.op_video is not None:
|
if self.op_video is not None:
|
||||||
self.op_video.stop()
|
self.op_video.stop()
|
||||||
if self.attract_video is not None:
|
if self.attract_video is not None:
|
||||||
self.attract_video.stop()
|
self.attract_video.stop()
|
||||||
for sound in self.sounds:
|
audio.unload_all_sounds()
|
||||||
if audio.is_sound_playing(sound):
|
tex.unload_textures()
|
||||||
audio.stop_sound(sound)
|
|
||||||
for zip in self.textures:
|
|
||||||
for texture in self.textures[zip]:
|
|
||||||
ray.unload_texture(texture)
|
|
||||||
self.screen_init = False
|
self.screen_init = False
|
||||||
return "ENTRY"
|
return "ENTRY"
|
||||||
|
|
||||||
@@ -82,7 +71,7 @@ class TitleScreen:
|
|||||||
self.state = State.WARNING
|
self.state = State.WARNING
|
||||||
elif self.state == State.WARNING:
|
elif self.state == State.WARNING:
|
||||||
if self.warning_board is None:
|
if self.warning_board is None:
|
||||||
self.warning_board = WarningScreen(get_current_ms(), self)
|
self.warning_board = WarningScreen(get_current_ms())
|
||||||
self.warning_board.update(get_current_ms(), self)
|
self.warning_board.update(get_current_ms(), self)
|
||||||
if self.warning_board.is_finished:
|
if self.warning_board.is_finished:
|
||||||
self.state = State.ATTRACT_VIDEO
|
self.state = State.ATTRACT_VIDEO
|
||||||
@@ -101,66 +90,59 @@ class TitleScreen:
|
|||||||
def update(self):
|
def update(self):
|
||||||
self.on_screen_start()
|
self.on_screen_start()
|
||||||
|
|
||||||
if self.fade_out is not None:
|
|
||||||
self.fade_out.update(get_current_ms())
|
self.fade_out.update(get_current_ms())
|
||||||
if self.fade_out.is_finished:
|
if self.fade_out.is_finished:
|
||||||
return self.on_screen_end()
|
return self.on_screen_end()
|
||||||
|
|
||||||
self.scene_manager()
|
self.scene_manager()
|
||||||
if is_l_don_pressed() or is_r_don_pressed():
|
if is_l_don_pressed() or is_r_don_pressed():
|
||||||
self.fade_out = Animation.create_fade(1000, initial_opacity=0.0, final_opacity=1.0)
|
self.fade_out.start()
|
||||||
audio.play_sound(self.sound_don)
|
audio.play_sound(self.sound_don)
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
if self.state == State.OP_VIDEO and self.op_video is not None:
|
if self.state == State.OP_VIDEO and self.op_video is not None:
|
||||||
self.op_video.draw()
|
self.op_video.draw()
|
||||||
elif self.state == State.WARNING and self.warning_board is not None:
|
elif self.state == State.WARNING and self.warning_board is not None:
|
||||||
bg_source = ray.Rectangle(0, 0, self.textures['keikoku'][0].width, self.textures['keikoku'][0].height)
|
tex.draw_texture('warning', 'background')
|
||||||
bg_dest = ray.Rectangle(0, 0, self.width, self.height)
|
self.warning_board.draw()
|
||||||
ray.draw_texture_pro(self.textures['keikoku'][0], bg_source, bg_dest, ray.Vector2(0,0), 0, ray.WHITE)
|
|
||||||
self.warning_board.draw(self)
|
|
||||||
elif self.state == State.ATTRACT_VIDEO and self.attract_video is not None:
|
elif self.state == State.ATTRACT_VIDEO and self.attract_video is not None:
|
||||||
self.attract_video.draw()
|
self.attract_video.draw()
|
||||||
|
|
||||||
if self.fade_out is not None:
|
tex.draw_texture('movie', 'background', color=ray.fade(ray.WHITE, self.fade_out.attribute))
|
||||||
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))
|
|
||||||
|
|
||||||
def draw_3d(self):
|
def draw_3d(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class WarningScreen:
|
class WarningScreen:
|
||||||
class X:
|
class X:
|
||||||
DELAY = 4250
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.resize = Animation.create_texture_resize(166.67, initial_size=1.0, final_size=1.5, delay=self.DELAY, reverse_delay=0)
|
self.resize = tex.get_animation(0)
|
||||||
self.fadein = Animation.create_fade(166.67, delay=self.DELAY, initial_opacity=0.0, final_opacity=1.0, reverse_delay=166.67)
|
self.resize.start()
|
||||||
self.fadein_2 = Animation.create_fade(166.67, delay=self.DELAY + self.fadein.duration, initial_opacity=0.0, final_opacity=1.0)
|
self.fadein = tex.get_animation(1)
|
||||||
|
self.fadein.start()
|
||||||
|
self.fadein_2 = tex.get_animation(2)
|
||||||
|
self.fadein_2.start()
|
||||||
self.sound_played = False
|
self.sound_played = False
|
||||||
|
|
||||||
def update(self, current_ms: float, sound, elapsed_time):
|
def update(self, current_ms: float, sound):
|
||||||
|
self.resize.update(current_ms)
|
||||||
self.fadein.update(current_ms)
|
self.fadein.update(current_ms)
|
||||||
self.fadein_2.update(current_ms)
|
self.fadein_2.update(current_ms)
|
||||||
self.resize.update(current_ms)
|
|
||||||
|
|
||||||
if self.DELAY + self.fadein.duration <= elapsed_time and not self.sound_played:
|
if self.resize.attribute > 1 and not self.sound_played:
|
||||||
audio.play_sound(sound)
|
audio.play_sound(sound)
|
||||||
self.sound_played = True
|
self.sound_played = True
|
||||||
|
|
||||||
def draw(self, texture):
|
def draw_bg(self):
|
||||||
scale = self.resize.attribute
|
tex.draw_texture('warning', 'x_lightred', color=ray.fade(ray.WHITE, self.fadein_2.attribute))
|
||||||
x_x = 150 + (texture.width//2) - ((texture.width * scale)//2)
|
|
||||||
x_y = 200 + (texture.height//2) - ((texture.height * scale)//2)
|
def draw_fg(self):
|
||||||
x_source = ray.Rectangle(0, 0, texture.width, texture.height)
|
tex.draw_texture('warning', 'x_red', color=ray.fade(ray.WHITE, self.fadein.attribute), scale=self.resize.attribute, center=True)
|
||||||
x_dest = ray.Rectangle(x_x, x_y, texture.width*scale, texture.height*scale)
|
|
||||||
ray.draw_texture_pro(texture, x_source, x_dest, ray.Vector2(0,0), 0, ray.fade(ray.WHITE, self.fadein.attribute))
|
|
||||||
|
|
||||||
class BachiHit:
|
class BachiHit:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.resize = Animation.create_texture_resize(233.34, initial_size=0.5, final_size=1.5)
|
self.resize = tex.get_animation(3)
|
||||||
self.fadein = Animation.create_fade(116.67, initial_opacity=0.0, final_opacity=1.0, reverse_delay=0)
|
self.fadein = tex.get_animation(4)
|
||||||
|
|
||||||
self.sound_played = False
|
self.sound_played = False
|
||||||
|
|
||||||
@@ -168,83 +150,55 @@ class WarningScreen:
|
|||||||
if not self.sound_played:
|
if not self.sound_played:
|
||||||
audio.play_sound(sound)
|
audio.play_sound(sound)
|
||||||
self.sound_played = True
|
self.sound_played = True
|
||||||
self.resize.start_ms = current_ms
|
self.fadein.start()
|
||||||
self.fadein.start_ms = current_ms
|
self.resize.start()
|
||||||
self.resize.update(current_ms)
|
self.resize.update(current_ms)
|
||||||
self.fadein.update(current_ms)
|
self.fadein.update(current_ms)
|
||||||
|
|
||||||
def draw(self, texture):
|
def draw(self):
|
||||||
scale = self.resize.attribute
|
tex.draw_texture('warning', 'bachi_hit', color=ray.fade(ray.WHITE, self.fadein.attribute), scale=self.resize.attribute, center=True)
|
||||||
hit_x = 350 + (texture.width//2) - ((texture.width * scale)//2)
|
if self.resize.attribute > 0 and self.sound_played:
|
||||||
hit_y = 225 + (texture.height//2) - ((texture.height * scale)//2)
|
tex.draw_texture('warning', 'bachi')
|
||||||
hit_source = ray.Rectangle(0, 0, texture.width, texture.height)
|
|
||||||
hit_dest = ray.Rectangle(hit_x, hit_y, texture.width*scale, texture.height*scale)
|
|
||||||
ray.draw_texture_pro(texture, hit_source, hit_dest, ray.Vector2(0,0), 0, ray.fade(ray.WHITE, self.fadein.attribute))
|
|
||||||
|
|
||||||
class Characters:
|
class Characters:
|
||||||
def __init__(self, current_ms: float, start_ms: float):
|
def __init__(self):
|
||||||
self.start_ms = start_ms
|
self.shadow_fade = tex.get_animation(5)
|
||||||
self.current_ms = current_ms
|
self.chara_0_frame = tex.get_animation(7)
|
||||||
self.shadow_fade = Animation.create_fade(50, delay=16.67, initial_opacity=0.75)
|
self.chara_1_frame = tex.get_animation(6)
|
||||||
|
self.chara_0_frame.start()
|
||||||
self.animation_sequence = [(300.00, 5, 4), (183.33, 6, 4), (166.67, 7, 4), (166.67, 8, 9), (166.67, 11, 9), (166.67, 12, 9), (166.67, 13, 9),
|
self.chara_1_frame.start()
|
||||||
(166.67, 5, 4), (150.00, 5, 4), (133.34, 6, 4), (133.34, 7, 4), (133.34, 8, 9), (133.34, 11, 9), (133.34, 12, 9), (133.34, 13, 9),
|
self.saved_frame = 0
|
||||||
(133.34, 5, 4), (116.67, 5, 4), (100.00, 6, 4), (100.00, 7, 4), (100.00, 8, 9), (100.00, 11, 9), (100.00, 12, 9), (100.00, 13, 9),
|
|
||||||
(100.00, 5, 4), (100.00, 5, 4), (83.330, 6, 4), (83.330, 7, 4), (83.330, 8, 9), (83.330, 11, 9), (83.330, 12, 9), (83.330, 13, 9),
|
|
||||||
(83.330, 5, 4), (83.330, 5, 4), (66.670, 6, 4), (66.670, 7, 4), (66.670, 8, 9), (66.670, 11, 9), (66.670, 12, 9), (66.670, 13, 9),
|
|
||||||
(66.670, 5, 4), (66.670, 5, 4), (66.670, 6, 4), (66.670, 7, 4), (66.670, 8, 9), (66.670, 11, 9), (66.670, 12, 9), (66.670, 13, 9),
|
|
||||||
(66.670, 5, 4), (66.670, 5, 4), (66.670, 6, 4), (66.670, 7, 4), (66.670, 8, 9), (66.670, 11, 9), (66.670, 12, 9), (66.670, 13, 9),
|
|
||||||
(66.670, 17, 16)]
|
|
||||||
|
|
||||||
|
|
||||||
self.time = 0
|
|
||||||
self.index_val = 0
|
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
|
|
||||||
def character_index(self, index: int) -> int:
|
|
||||||
elapsed_time = self.current_ms - self.start_ms
|
|
||||||
delay = 566.67
|
|
||||||
if self.index_val == len(self.animation_sequence)-1:
|
|
||||||
return int(self.animation_sequence[len(self.animation_sequence)-1][index])
|
|
||||||
elif elapsed_time <= delay:
|
|
||||||
return int(self.animation_sequence[0][index])
|
|
||||||
elif elapsed_time >= delay + self.time:
|
|
||||||
new_index = self.animation_sequence[self.index_val][index]
|
|
||||||
self.index_val += 1
|
|
||||||
self.shadow_fade.start_ms = self.current_ms
|
|
||||||
self.shadow_fade.duration = int(self.animation_sequence[self.index_val][0])
|
|
||||||
self.time += self.animation_sequence[self.index_val][0]
|
|
||||||
return int(new_index)
|
|
||||||
else:
|
|
||||||
return int(self.animation_sequence[self.index_val][index])
|
|
||||||
|
|
||||||
def update(self, current_ms: float):
|
def update(self, current_ms: float):
|
||||||
self.shadow_fade.update(current_ms)
|
self.shadow_fade.update(current_ms)
|
||||||
|
self.chara_1_frame.update(current_ms)
|
||||||
|
self.chara_0_frame.update(current_ms)
|
||||||
self.current_ms = current_ms
|
self.current_ms = current_ms
|
||||||
self.is_finished = True if self.character_index(1) == self.animation_sequence[-1][1] else False
|
if self.chara_1_frame.attribute != self.saved_frame:
|
||||||
|
self.saved_frame = self.chara_1_frame.attribute
|
||||||
|
if not self.shadow_fade.is_started:
|
||||||
|
self.shadow_fade.start()
|
||||||
|
else:
|
||||||
|
self.shadow_fade.restart()
|
||||||
|
self.is_finished = self.chara_1_frame.is_finished
|
||||||
|
def draw(self, fade: ray.Color, fade_2: ray.Color):
|
||||||
|
tex.draw_texture('warning', 'chara_0_shadow', color=fade_2)
|
||||||
|
tex.draw_texture('warning', 'chara_0', frame=self.chara_0_frame.attribute, color=fade)
|
||||||
|
|
||||||
def draw(self, textures, fade: ray.Color, fade_2: ray.Color, y: int):
|
tex.draw_texture('warning', 'chara_1_shadow', color=fade_2)
|
||||||
ray.draw_texture(textures['keikoku'][2], 135, y+textures['keikoku'][4].height+110, fade_2)
|
if -1 < self.chara_1_frame.attribute-1 < 7:
|
||||||
ray.draw_texture(textures['keikoku'][self.character_index(2)], 115, y+150, fade)
|
tex.draw_texture('warning', 'chara_1', frame=self.chara_1_frame.attribute-1, color=ray.fade(ray.WHITE, self.shadow_fade.attribute))
|
||||||
|
tex.draw_texture('warning', 'chara_1', frame=self.chara_1_frame.attribute, color=fade)
|
||||||
ray.draw_texture(textures['keikoku'][3], 360, y+textures['keikoku'][5].height+60, fade_2)
|
|
||||||
|
|
||||||
if 6 < self.character_index(1) < 17:
|
|
||||||
ray.draw_texture(textures['keikoku'][self.character_index(1) - 1], 315, y+100, ray.fade(ray.WHITE, self.shadow_fade.attribute))
|
|
||||||
ray.draw_texture(textures['keikoku'][self.character_index(1)], 315, y+100, fade)
|
|
||||||
if self.character_index(1) == 17:
|
|
||||||
ray.draw_texture(textures['keikoku'][19], 350, y+135, ray.WHITE)
|
|
||||||
|
|
||||||
class Board:
|
class Board:
|
||||||
def __init__(self, screen_width, screen_height, texture):
|
def __init__(self):
|
||||||
#Move warning board down from top of screen
|
self.move_down = tex.get_animation(10)
|
||||||
self.move_down = Animation.create_move(266.67, total_distance=screen_height + ((screen_height - texture.height)//2) + 20, start_position=-720)
|
self.move_down.start()
|
||||||
|
self.move_up = tex.get_animation(11)
|
||||||
#Move warning board up a little bit
|
self.move_up.start()
|
||||||
self.move_up = Animation.create_move(116.67, start_position=92 + 20, delay=self.move_down.duration, total_distance =-30)
|
self.move_center = tex.get_animation(12)
|
||||||
|
self.move_center.start()
|
||||||
#And finally into its correct position
|
|
||||||
self.move_center = Animation.create_move(116.67, start_position=82, delay=self.move_down.duration + self.move_up.duration, total_distance=10)
|
|
||||||
self.y_pos = 0
|
self.y_pos = 0
|
||||||
|
|
||||||
def update(self, current_ms):
|
def update(self, current_ms):
|
||||||
@@ -252,29 +206,29 @@ class WarningScreen:
|
|||||||
self.move_up.update(current_ms)
|
self.move_up.update(current_ms)
|
||||||
self.move_center.update(current_ms)
|
self.move_center.update(current_ms)
|
||||||
if self.move_up.is_finished:
|
if self.move_up.is_finished:
|
||||||
self.y_pos = int(self.move_center.attribute)
|
self.y_pos = self.move_center.attribute
|
||||||
elif self.move_down.is_finished:
|
elif self.move_down.is_finished:
|
||||||
self.y_pos = int(self.move_up.attribute)
|
self.y_pos = self.move_up.attribute
|
||||||
else:
|
else:
|
||||||
self.y_pos = int(self.move_down.attribute)
|
self.y_pos = self.move_down.attribute
|
||||||
|
tex.update_attr('warning', 'warning_box', 'y', self.y_pos)
|
||||||
|
|
||||||
def draw(self, texture):
|
def draw(self):
|
||||||
ray.draw_texture(texture, 0, self.y_pos, ray.WHITE)
|
tex.draw_texture('warning', 'warning_box')
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, current_ms: float, title_screen: TitleScreen):
|
def __init__(self, current_ms: float):
|
||||||
self.start_ms = current_ms
|
self.start_ms = current_ms
|
||||||
|
|
||||||
self.fade_in = Animation.create_fade(300, delay=266.67, initial_opacity=0.0, final_opacity=1.0)
|
self.fade_in = tex.get_animation(8)
|
||||||
self.fade_out = Animation.create_fade(500, delay=1000, initial_opacity=0.0, final_opacity=1.0)
|
self.fade_in.start()
|
||||||
|
self.fade_out = tex.get_animation(9)
|
||||||
|
self.fade_out.start()
|
||||||
|
|
||||||
self.board = self.Board(title_screen.width, title_screen.height, title_screen.textures['keikoku'][1])
|
self.board = self.Board()
|
||||||
self.warning_x = self.X()
|
self.warning_x = self.X()
|
||||||
self.warning_bachi_hit = self.BachiHit()
|
self.warning_bachi_hit = self.BachiHit()
|
||||||
self.characters = self.Characters(current_ms, self.start_ms)
|
self.characters = self.Characters()
|
||||||
|
|
||||||
self.source_rect = ray.Rectangle(0, 0, title_screen.texture_black.width, title_screen.texture_black.height)
|
|
||||||
self.dest_rect = ray.Rectangle(0, 0, title_screen.width, title_screen.height)
|
|
||||||
|
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
|
|
||||||
@@ -284,8 +238,12 @@ class WarningScreen:
|
|||||||
self.fade_out.update(current_ms)
|
self.fade_out.update(current_ms)
|
||||||
delay = 566.67
|
delay = 566.67
|
||||||
elapsed_time = current_ms - self.start_ms
|
elapsed_time = current_ms - self.start_ms
|
||||||
self.warning_x.update(current_ms, title_screen.sound_warning_error, elapsed_time)
|
self.warning_x.update(current_ms, title_screen.sound_warning_error)
|
||||||
self.characters.update(current_ms)
|
self.characters.update(current_ms)
|
||||||
|
tex.update_attr('warning', 'chara_0', 'y', self.board.y_pos)
|
||||||
|
tex.update_attr('warning', 'chara_0_shadow', 'y', self.board.y_pos)
|
||||||
|
tex.update_attr('warning', 'chara_1_shadow', 'y', self.board.y_pos)
|
||||||
|
tex.update_attr('warning', 'chara_1', 'y', self.board.y_pos)
|
||||||
|
|
||||||
if self.characters.is_finished:
|
if self.characters.is_finished:
|
||||||
self.warning_bachi_hit.update(current_ms, title_screen.sound_bachi_hit)
|
self.warning_bachi_hit.update(current_ms, title_screen.sound_bachi_hit)
|
||||||
@@ -297,16 +255,14 @@ class WarningScreen:
|
|||||||
|
|
||||||
self.is_finished = self.fade_out.is_finished
|
self.is_finished = self.fade_out.is_finished
|
||||||
|
|
||||||
def draw(self, title_screen: TitleScreen):
|
def draw(self):
|
||||||
fade = ray.fade(ray.WHITE, self.fade_in.attribute)
|
fade = ray.fade(ray.WHITE, self.fade_in.attribute)
|
||||||
fade_2 = ray.fade(ray.WHITE, self.fade_in.attribute if self.fade_in.attribute < 0.75 else 0.75)
|
fade_2 = ray.fade(ray.WHITE, min(self.fade_in.attribute, 0.75))
|
||||||
self.board.draw(title_screen.textures['keikoku'][1])
|
|
||||||
ray.draw_texture(title_screen.textures['keikoku'][15], 150, 200, ray.fade(ray.WHITE, self.warning_x.fadein_2.attribute))
|
|
||||||
|
|
||||||
self.characters.draw(title_screen.textures, fade, fade_2, self.board.y_pos)
|
self.board.draw()
|
||||||
|
self.warning_x.draw_bg()
|
||||||
|
self.characters.draw(fade, fade_2)
|
||||||
|
self.warning_x.draw_fg()
|
||||||
|
self.warning_bachi_hit.draw()
|
||||||
|
|
||||||
self.warning_x.draw(title_screen.textures['keikoku'][14])
|
tex.draw_texture('movie', 'background', color=ray.fade(ray.WHITE, self.fade_out.attribute))
|
||||||
|
|
||||||
self.warning_bachi_hit.draw(title_screen.textures['keikoku'][18])
|
|
||||||
|
|
||||||
ray.draw_texture_pro(title_screen.texture_black, self.source_rect, self.dest_rect, ray.Vector2(0,0), 0, ray.fade(ray.WHITE, self.fade_out.attribute))
|
|
||||||
|
|||||||
Reference in New Issue
Block a user