|
|
@@ -348,7 +348,7 @@ def build_parts_skeleton_json(char_id, parts, atlas_w, atlas_h, animations):
|
|
|
}
|
|
|
|
|
|
|
|
|
-def build_parts_character(char_id, part_images, out_dir, animations, layout_parts):
|
|
|
+def build_parts_character(char_id, part_images, out_dir, animations, layout_parts, write_preview=True):
|
|
|
"""多部件 Boss:part_images {part_id: PIL RGBA} -> 单 atlas + 多骨骼 JSON。"""
|
|
|
os.makedirs(out_dir, exist_ok=True)
|
|
|
packed = []
|
|
|
@@ -376,7 +376,8 @@ def build_parts_character(char_id, part_images, out_dir, animations, layout_part
|
|
|
skel = build_parts_skeleton_json(char_id, packed, atlas_w, atlas_h, animations)
|
|
|
with open(os.path.join(out_dir, f"{char_id}.json"), "w", encoding="utf-8") as f:
|
|
|
json.dump(skel, f, ensure_ascii=False, indent=2)
|
|
|
- write_parts_preview(char_id, packed, out_dir)
|
|
|
+ if write_preview:
|
|
|
+ write_parts_preview(char_id, packed, out_dir)
|
|
|
return png_path
|
|
|
|
|
|
|
|
|
@@ -384,6 +385,23 @@ def write_parts_preview(char_id, packed, out_dir):
|
|
|
"""Write a human-readable assembled preview for multi-part characters."""
|
|
|
canvas = Image.new("RGBA", (1000, 1000), (0, 0, 0, 0))
|
|
|
by_id = {p["id"]: p for p in packed}
|
|
|
+ world_cache = {}
|
|
|
+
|
|
|
+ def world_pos(pid):
|
|
|
+ if pid in world_cache:
|
|
|
+ return world_cache[pid]
|
|
|
+ p = by_id.get(pid)
|
|
|
+ if not p:
|
|
|
+ return 0, 0
|
|
|
+ px, py = p.get("x", 0), p.get("y", 0)
|
|
|
+ parent = p.get("parent")
|
|
|
+ if parent and parent != "root":
|
|
|
+ ox, oy = world_pos(parent)
|
|
|
+ px += ox
|
|
|
+ py += oy
|
|
|
+ world_cache[pid] = (px, py)
|
|
|
+ return px, py
|
|
|
+
|
|
|
order = [
|
|
|
"cape", "defeated_hero_shadow", "left_leg", "right_leg", "torso",
|
|
|
"left_arm", "right_arm", "greatsword", "coin_bag", "head",
|
|
|
@@ -394,8 +412,9 @@ def write_parts_preview(char_id, packed, out_dir):
|
|
|
if not p:
|
|
|
continue
|
|
|
img = p["img"]
|
|
|
- x = int(500 + p.get("x", 0) - img.width / 2)
|
|
|
- y = int(700 - p.get("y", 0) - img.height / 2)
|
|
|
+ wx, wy = world_pos(pid)
|
|
|
+ x = int(500 + wx - img.width / 2)
|
|
|
+ y = int(760 - wy - img.height / 2)
|
|
|
canvas.paste(img, (x, y), img)
|
|
|
preview = trim_to_content(canvas, pad=16)
|
|
|
preview.save(os.path.join(out_dir, f"{char_id}_preview.png"))
|
|
|
@@ -444,7 +463,13 @@ def write_parts_preview_from_files(char_id, out_dir):
|
|
|
if not r:
|
|
|
continue
|
|
|
img = atlas.crop((r["x"], r["y"], r["x"] + r["w"], r["y"] + r["h"]))
|
|
|
- packed.append({"id": name, "img": img, "x": b.get("x", 0), "y": b.get("y", 0)})
|
|
|
+ packed.append({
|
|
|
+ "id": name,
|
|
|
+ "img": img,
|
|
|
+ "x": b.get("x", 0),
|
|
|
+ "y": b.get("y", 0),
|
|
|
+ "parent": b.get("parent", "root"),
|
|
|
+ })
|
|
|
if not packed:
|
|
|
return ""
|
|
|
write_parts_preview(char_id, packed, out_dir)
|