mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 11:40:13 +01:00
more graphics wrapper updates
This commit is contained in:
@@ -4,6 +4,7 @@ from pathlib import Path
|
||||
import pyray as ray
|
||||
|
||||
from libs.animation import Animation
|
||||
from libs.texture import TextureWrapper
|
||||
from libs.utils import load_all_textures_from_zip
|
||||
|
||||
|
||||
@@ -11,10 +12,12 @@ class Background:
|
||||
def __init__(self, screen_width: int, screen_height: int):
|
||||
self.screen_width = screen_width
|
||||
self.screen_height = screen_height
|
||||
self.donbg = DonBG.create(self.screen_width, self.screen_height, random.randint(1, 6), 1)
|
||||
self.tex_wrapper = TextureWrapper()
|
||||
self.tex_wrapper.load_animations('background')
|
||||
self.donbg = DonBG.create(self.tex_wrapper, self.screen_width, self.screen_height, random.randint(1, 6), 1)
|
||||
self.bg_normal = BGNormal.create(self.screen_width, self.screen_height, random.randint(1, 5))
|
||||
self.bg_fever = BGFever.create(self.screen_width, self.screen_height, 4)
|
||||
self.footer = Footer(self.screen_width, self.screen_height, random.randint(1, 3))
|
||||
self.footer = Footer(self.tex_wrapper, random.randint(0, 2))
|
||||
self.is_clear = False
|
||||
def update(self, current_time_ms: float, is_clear: bool):
|
||||
if not self.is_clear and is_clear:
|
||||
@@ -27,27 +30,27 @@ class Background:
|
||||
self.bg_normal.draw()
|
||||
if self.is_clear:
|
||||
self.bg_fever.draw()
|
||||
self.footer.draw()
|
||||
self.footer.draw(self.tex_wrapper)
|
||||
self.donbg.draw()
|
||||
|
||||
def unload(self):
|
||||
self.donbg.unload()
|
||||
self.bg_normal.unload()
|
||||
self.bg_fever.unload()
|
||||
self.footer.unload()
|
||||
|
||||
class DonBG:
|
||||
|
||||
@staticmethod
|
||||
def create(screen_width: int, screen_height: int, index: int, player_num: int):
|
||||
def create(tex: TextureWrapper, screen_width: int, screen_height: int, index: int, player_num: int):
|
||||
map = [None, DonBG1, DonBG2, DonBG3, DonBG4, DonBG5, DonBG6]
|
||||
selected_obj = map[index]
|
||||
return selected_obj(index, screen_width, screen_height, player_num)
|
||||
return selected_obj(tex, index, screen_width, screen_height, player_num)
|
||||
|
||||
class DonBGBase:
|
||||
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
self.screen_width = screen_width
|
||||
self.screen_height = screen_height
|
||||
#tex.load_zip('background', f'donbg/{index}_{player_num}')
|
||||
self.player_num = player_num
|
||||
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')))
|
||||
@@ -73,8 +76,8 @@ class DonBGBase:
|
||||
ray.unload_texture(texture)
|
||||
|
||||
class DonBG1(DonBGBase):
|
||||
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
super().__init__(index, screen_width, screen_height, player_num)
|
||||
def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
super().__init__(tex, 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.start()
|
||||
def update(self, current_time_ms: float, is_clear: bool):
|
||||
@@ -100,8 +103,8 @@ class DonBG1(DonBGBase):
|
||||
ray.draw_texture(texture, i + int(self.move.attribute * (texture.width/top_texture.width)*3), int(self.overlay_move.attribute) + 105, color)
|
||||
|
||||
class DonBG2(DonBGBase):
|
||||
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
super().__init__(index, screen_width, screen_height, player_num)
|
||||
def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
super().__init__(tex, 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.start()
|
||||
def update(self, current_time_ms: float, is_clear: bool):
|
||||
@@ -123,8 +126,8 @@ class DonBG2(DonBGBase):
|
||||
ray.draw_texture(texture, i + int(self.move.attribute), int(self.overlay_move.attribute) - 25, color)
|
||||
|
||||
class DonBG3(DonBGBase):
|
||||
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
super().__init__(index, screen_width, screen_height, player_num)
|
||||
def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
super().__init__(tex, index, screen_width, screen_height, player_num)
|
||||
duration = 266
|
||||
bounce_distance = 40
|
||||
self.bounce_up = Animation.create_move(duration, total_distance=-bounce_distance, ease_out='quadratic')
|
||||
@@ -162,8 +165,8 @@ class DonBG3(DonBGBase):
|
||||
ray.draw_texture(texture, i + int(self.move.attribute*2), int(self.bounce_up.attribute) - int(self.bounce_down.attribute) - 25 + int(self.overlay_move.attribute) + int(self.overlay_move_2.attribute), color)
|
||||
|
||||
class DonBG4(DonBGBase):
|
||||
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
super().__init__(index, screen_width, screen_height, player_num)
|
||||
def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
super().__init__(tex, 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.start()
|
||||
def update(self, current_time_ms: float, is_clear: bool):
|
||||
@@ -186,8 +189,8 @@ class DonBG4(DonBGBase):
|
||||
ray.draw_texture(texture, i + int(self.move.attribute), int(self.overlay_move.attribute) - 25, color)
|
||||
|
||||
class DonBG5(DonBGBase):
|
||||
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
super().__init__(index, screen_width, screen_height, player_num)
|
||||
def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
super().__init__(tex, index, screen_width, screen_height, player_num)
|
||||
duration = 266
|
||||
bounce_distance = 40
|
||||
self.bounce_up = Animation.create_move(duration, total_distance=-bounce_distance, ease_out='quadratic')
|
||||
@@ -221,8 +224,8 @@ class DonBG5(DonBGBase):
|
||||
ray.draw_texture(texture, i + int((self.move.attribute * (texture.width/top_texture.width))*2), int(self.bounce_up.attribute) - int(self.bounce_down.attribute) - int(self.adjust.attribute), color)
|
||||
|
||||
class DonBG6(DonBGBase):
|
||||
def __init__(self, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
super().__init__(index, screen_width, screen_height, player_num)
|
||||
def __init__(self, tex: TextureWrapper, index: int, screen_width: int, screen_height: int, player_num: int):
|
||||
super().__init__(tex, 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.start()
|
||||
def update(self, current_time_ms: float, is_clear: bool):
|
||||
@@ -498,14 +501,8 @@ class BGFever4(BGFeverBase):
|
||||
ray.draw_texture(self.textures[self.name][2], self.textures[self.name][2].width -int(self.horizontal_move.attribute), y, ray.WHITE)
|
||||
|
||||
class Footer:
|
||||
def __init__(self, screen_width: int, screen_height: int, index: int):
|
||||
self.screen_width = screen_width
|
||||
self.screen_height = screen_height
|
||||
self.name = 'dodai_a_' + str(index).zfill(2)
|
||||
self.textures = (load_all_textures_from_zip(Path(f'Graphics/lumendata/enso_original/{self.name}.zip')))
|
||||
def unload(self):
|
||||
for texture_group in self.textures:
|
||||
for texture in self.textures[texture_group]:
|
||||
ray.unload_texture(texture)
|
||||
def draw(self):
|
||||
ray.draw_texture(self.textures[self.name][0], 0, self.screen_height - self.textures[self.name][0].height + 20, ray.WHITE)
|
||||
def __init__(self, tex: TextureWrapper, index: int):
|
||||
self.index = index
|
||||
tex.load_zip('background', 'footer')
|
||||
def draw(self, tex: TextureWrapper):
|
||||
tex.draw_texture('footer', str(self.index))
|
||||
|
||||
102
libs/texture.py
102
libs/texture.py
@@ -63,6 +63,55 @@ class TextureWrapper:
|
||||
tex_object.x2 = tex_mapping.get("x2", tex_object.width)
|
||||
tex_object.y2 = tex_mapping.get("y2", tex_object.height)
|
||||
|
||||
def load_animations(self, screen_name: str):
|
||||
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()))
|
||||
|
||||
def load_zip(self, screen_name: str, subset: str):
|
||||
zip = (self.graphics_path / screen_name / subset).with_suffix('.zip')
|
||||
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 load_screen_textures(self, screen_name: str) -> None:
|
||||
self.unload_textures()
|
||||
screen_path = self.graphics_path / screen_name
|
||||
@@ -72,51 +121,18 @@ class TextureWrapper:
|
||||
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}")
|
||||
self.load_zip(screen_name, zip.name)
|
||||
|
||||
|
||||
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: float = 0, y: float = 0, x2: float = 0, y2: float = 0, origin: ray.Vector2 = ray.Vector2(0,0), rotation: float = 0) -> None:
|
||||
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: float = 0, y: float = 0, x2: float = 0, y2: float = 0,
|
||||
origin: ray.Vector2 = ray.Vector2(0,0), rotation: float = 0, fade: float = 1.1) -> None:
|
||||
mirror_x = -1 if mirror == 'horizontal' else 1
|
||||
mirror_y = -1 if mirror == 'vertical' else 1
|
||||
if fade != 1.1:
|
||||
final_color = ray.fade(color, fade)
|
||||
else:
|
||||
final_color = color
|
||||
tex_object = self.textures[subset][texture]
|
||||
source_rect = ray.Rectangle(0, 0, tex_object.width * mirror_x, tex_object.height * mirror_y)
|
||||
if center:
|
||||
@@ -128,10 +144,10 @@ class TextureWrapper:
|
||||
raise Exception("Texture was marked as multiframe but is only 1 texture")
|
||||
if frame >= len(tex_object.texture):
|
||||
raise Exception(f"Frame {frame} not available in iterable texture {tex_object.name}")
|
||||
ray.draw_texture_pro(tex_object.texture[frame], source_rect, dest_rect, origin, rotation, color)
|
||||
ray.draw_texture_pro(tex_object.texture[frame], source_rect, dest_rect, origin, rotation, final_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, origin, rotation, color)
|
||||
ray.draw_texture_pro(tex_object.texture, source_rect, dest_rect, origin, rotation, final_color)
|
||||
|
||||
tex = TextureWrapper()
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
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:
|
||||
def __init__(self, title: str, subtitle: str, is_second: bool = False) -> None:
|
||||
self.is_finished = False
|
||||
self.rainbow_up = global_data.tex.get_animation(0)
|
||||
self.mini_up = global_data.tex.get_animation(1)
|
||||
@@ -14,7 +13,7 @@ class Transition:
|
||||
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
|
||||
self.is_second = is_second
|
||||
|
||||
def start(self):
|
||||
self.rainbow_up.start()
|
||||
@@ -67,59 +66,3 @@ class Transition:
|
||||
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()
|
||||
|
||||
@@ -197,11 +197,6 @@ def is_r_kat_pressed() -> bool:
|
||||
|
||||
return False
|
||||
|
||||
def draw_scaled_texture(texture: ray.Texture, x: int, y: int, scale: float, color: ray.Color) -> None:
|
||||
src_rect = ray.Rectangle(0, 0, texture.width, texture.height)
|
||||
dst_rect = ray.Rectangle(x, y, texture.width*scale, texture.height*scale)
|
||||
ray.draw_texture_pro(texture, src_rect, dst_rect, ray.Vector2(0, 0), 0, color)
|
||||
|
||||
@dataclass
|
||||
class SessionData:
|
||||
selected_difficulty: int = 0
|
||||
|
||||
Reference in New Issue
Block a user