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>
This commit is contained in:
2026-06-16 15:30:58 +08:00
parent cba5105908
commit d393302388
6248 changed files with 17322729 additions and 11036 deletions

View File

@@ -0,0 +1,165 @@
#!/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()