mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 19:50:12 +01:00
192 lines
9.4 KiB
Python
192 lines
9.4 KiB
Python
import copy
|
|
import json
|
|
import os
|
|
import tempfile
|
|
import zipfile
|
|
from pathlib import Path
|
|
from typing import Optional, Union
|
|
|
|
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: list[int] = [0]
|
|
self.y: list[int] = [0]
|
|
self.x2: list[int] = [self.width]
|
|
self.y2: list[int] = [self.height]
|
|
self.controllable: list[bool] = [False]
|
|
|
|
class TextureWrapper:
|
|
def __init__(self):
|
|
self.textures: dict[str, dict[str, Texture]] = dict()
|
|
self.animations: dict[int, BaseAnimation] = dict()
|
|
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, is_copy: bool = False):
|
|
if index not in self.animations:
|
|
raise Exception(f"Unable to find id {index} in loaded animations")
|
|
if is_copy:
|
|
new_anim = copy.deepcopy(self.animations[index])
|
|
if self.animations[index].loop:
|
|
new_anim.start()
|
|
return new_anim
|
|
if self.animations[index].loop:
|
|
self.animations[index].start()
|
|
return self.animations[index]
|
|
|
|
def _read_tex_obj_data(self, tex_mapping: dict | list, tex_object: Texture):
|
|
if isinstance(tex_mapping, list):
|
|
for i in range(len(tex_mapping)):
|
|
if i == 0:
|
|
tex_object.x[i] = tex_mapping[i].get("x", 0)
|
|
tex_object.y[i] = tex_mapping[i].get("y", 0)
|
|
tex_object.x2[i] = tex_mapping[i].get("x2", tex_object.width)
|
|
tex_object.y2[i] = tex_mapping[i].get("y2", tex_object.height)
|
|
tex_object.controllable[i] = tex_mapping[i].get("controllable", False)
|
|
else:
|
|
tex_object.x.append(tex_mapping[i].get("x", 0))
|
|
tex_object.y.append(tex_mapping[i].get("y", 0))
|
|
tex_object.x2.append(tex_mapping[i].get("x2", tex_object.width))
|
|
tex_object.y2.append(tex_mapping[i].get("y2", tex_object.height))
|
|
tex_object.controllable.append(tex_mapping[i].get("controllable", False))
|
|
else:
|
|
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)]
|
|
tex_object.controllable = [tex_mapping.get("controllable", False)]
|
|
|
|
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:
|
|
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
|
|
self.load_zip(screen_name, zip.name)
|
|
|
|
def control(self, tex_object: Texture, index: int = 0):
|
|
distance = 1
|
|
if ray.is_key_down(ray.KeyboardKey.KEY_LEFT_SHIFT):
|
|
distance = 10
|
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_LEFT):
|
|
tex_object.x[index] -= distance
|
|
print(f"{tex_object.name}: {tex_object.x[index]}, {tex_object.y[index]}")
|
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_RIGHT):
|
|
tex_object.x[index] += distance
|
|
print(f"{tex_object.name}: {tex_object.x[index]}, {tex_object.y[index]}")
|
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_UP):
|
|
tex_object.y[index] -= distance
|
|
print(f"{tex_object.name}: {tex_object.x[index]}, {tex_object.y[index]}")
|
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_DOWN):
|
|
tex_object.y[index] += distance
|
|
print(f"{tex_object.name}: {tex_object.x[index]}, {tex_object.y[index]}")
|
|
|
|
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,
|
|
index: int = 0, src: Optional[ray.Rectangle] = None) -> 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]
|
|
if src is not None:
|
|
source_rect = src
|
|
else:
|
|
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[index] + (tex_object.width//2) - ((tex_object.width * scale)//2) + x, tex_object.y[index] + (tex_object.height//2) - ((tex_object.height * scale)//2) + y, tex_object.x2[index]*scale + x2, tex_object.y2[index]*scale + y2)
|
|
else:
|
|
dest_rect = ray.Rectangle(tex_object.x[index] + x, tex_object.y[index] + y, tex_object.x2[index]*scale + x2, tex_object.y2[index]*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")
|
|
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, 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, final_color)
|
|
if tex_object.controllable[index]:
|
|
self.control(tex_object)
|
|
|
|
tex = TextureWrapper()
|