Files
cocos/tools/build_theme_tile_meta.py
刘宇飞 d393302388 Complete Cocos Creator port with level bundles, themes, and tooling.
Adds level prefabs, theme assets, audio, extensions, and deployment scripts for the Unity WebGL migration.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 15:30:58 +08:00

166 lines
4.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""从 Cocos 贴图 + Unity pivot 生成 tile-display-meta.json裁剪后可见尺寸"""
from __future__ import annotations
import json
import re
import struct
from pathlib import Path
UNITY_THEMES = {
"silu": "silu",
"snow": "snow",
"sanxing": "sanxing",
"chinese": "Chinese",
"numMan": "numMan",
"redarmy": "redArmy",
"default": "Level",
}
TILE_NAMES = [
"Baseblock",
"JumpBlock",
"WallBlock",
"kuai11",
"Decor23",
"素材切图-23",
"素材切图2-23",
"小游戏素材红色_03",
]
def png_size(path: Path) -> tuple[int, int]:
with path.open("rb") as f:
f.read(16)
return struct.unpack(">II", f.read(8))
def alpha_bbox(png_path: Path) -> tuple[int, int, int, int] | None:
try:
from PIL import Image
except ImportError:
return None
try:
img = Image.open(png_path).convert("RGBA")
return img.getbbox()
except Exception:
return None
def read_unity_sprite_meta(meta_path: Path) -> dict | None:
if not meta_path.is_file():
return None
text = meta_path.read_text(encoding="utf-8")
pivot = re.search(r"spritePivot:\s*\{x:\s*([^,]+),\s*y:\s*([^}]+)\}", text)
ppu = re.search(r"spritePixelsToUnits:\s*(\d+(?:\.\d+)?)", text)
if not pivot:
return None
return {
"pivotX": float(pivot.group(1)),
"pivotY": float(pivot.group(2)),
"ppu": float(ppu.group(1)) if ppu else 100.0,
}
def resolve_draw_rect(
png_path: Path,
full_w: int,
full_h: int,
pivot_x: float,
pivot_y: float,
tile_name: str,
) -> dict:
bbox = alpha_bbox(png_path)
if not bbox:
return {
"width": full_w,
"height": full_h,
"pivotX": pivot_x,
"pivotY": pivot_y,
"fitMul": 1.0,
}
left, top, right, bottom = bbox
tw, th = right - left, bottom - top
if tw <= 0 or th <= 0 or (tw >= full_w and th >= full_h):
return {
"width": full_w,
"height": full_h,
"pivotX": pivot_x,
"pivotY": pivot_y,
"fitMul": 1.0,
}
pivot_bottom = pivot_y * full_h
trim_bottom = full_h - bottom
pivot_bottom_trim = pivot_bottom - trim_bottom
meta_pivot_y = max(0.0, min(1.0, pivot_bottom_trim / th))
meta_pivot_x = max(0.0, min(1.0, (pivot_x * full_w - left) / tw))
fit_mul = 1.0
out_pivot_y = meta_pivot_y
# kuai11 篝火:底座贴齐地面格,略放大消除缝隙
if tile_name == "kuai11":
fit_mul = 1.12
# 底座在裁剪图底部pivot 放低使底座对齐格子
out_pivot_y = max(0.28, min(0.42, meta_pivot_y * 0.45))
return {
"width": tw,
"height": th,
"pivotX": round(meta_pivot_x, 4),
"pivotY": round(out_pivot_y, 4),
"fitMul": fit_mul,
}
def build_theme(cocos_tex: Path, unity_tex: Path, unity_folder: str, cocos_key: str) -> dict:
theme_dir = unity_tex if unity_folder == "Level" else unity_tex / unity_folder
cocos_dir = cocos_tex if cocos_key == "default" else cocos_tex / cocos_key
tiles: dict[str, dict] = {}
for name in TILE_NAMES:
png = cocos_dir / f"{name}.png"
if not png.is_file():
if name == "Decor23":
png = cocos_dir / "素材切图-23.png"
elif name == "素材切图-23":
png = cocos_dir / "Decor23.png"
if not png.is_file():
continue
unity_png = theme_dir / png.name
meta = read_unity_sprite_meta(unity_png.with_suffix(".png.meta"))
if not meta:
continue
w, h = png_size(png)
draw = resolve_draw_rect(png, w, h, meta["pivotX"], meta["pivotY"], name)
tiles[name] = {**draw, "ppu": meta["ppu"]}
return tiles
def main():
import argparse
ap = argparse.ArgumentParser()
ap.add_argument("--unity-root", required=True)
ap.add_argument("--out", default="assets/resources/theme/tile-display-meta.json")
args = ap.parse_args()
project = Path(__file__).resolve().parent.parent
unity_tex = Path(args.unity_root) / "Assets" / "Texture"
cocos_tex = project / "assets/resources/textures"
themes: dict[str, dict] = {}
for cocos_key, unity_folder in UNITY_THEMES.items():
tiles = build_theme(cocos_tex, unity_tex, unity_folder, cocos_key)
if tiles:
themes[cocos_key] = tiles
print(f" {cocos_key}: {len(tiles)} tiles")
out = project / args.out
out.parent.mkdir(parents=True, exist_ok=True)
payload = {"version": 1, "themes": themes}
out.write_text(json.dumps(payload, indent=2, ensure_ascii=False), encoding="utf-8")
print(f"Wrote -> {out}")
if __name__ == "__main__":
main()