Adds level prefabs, theme assets, audio, extensions, and deployment scripts for the Unity WebGL migration. Co-authored-by: Cursor <cursoragent@cursor.com>
189 lines
4.9 KiB
Python
189 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
烘焙「地图模块」预制体(对齐 Unity Tile Palette 中的单个 Tile)。
|
||
|
||
输出: assets/resources/map-tiles/MapTile_*.prefab
|
||
在关卡编辑器右侧面板中作为笔刷模块使用。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import random
|
||
import string
|
||
import uuid
|
||
from pathlib import Path
|
||
|
||
LAYER_DEFAULT = 1073741824
|
||
|
||
CELL = 56
|
||
TILE_SIZE = CELL * 0.9
|
||
|
||
# 与 Unity SILU 调色板一致
|
||
MAP_TILES = [
|
||
{
|
||
"name": "MapTile_Baseblock",
|
||
"display": "地面 Baseblock",
|
||
"layer": "ground",
|
||
"tileKey": "Baseblock",
|
||
"texture": "textures/silu/Baseblock",
|
||
"spriteUuid": "5625da25-9915-416f-be60-c6decb355672@f9941",
|
||
"alpha": 255,
|
||
},
|
||
{
|
||
"name": "MapTile_JumpBlock",
|
||
"display": "跳跃 JumpBlock",
|
||
"layer": "ground",
|
||
"tileKey": "JumpBlock",
|
||
"texture": "textures/silu/JumpBlock",
|
||
"spriteUuid": None,
|
||
"alpha": 255,
|
||
},
|
||
{
|
||
"name": "MapTile_WallBlock",
|
||
"display": "墙 WallBlock",
|
||
"layer": "border",
|
||
"tileKey": "WallBlock",
|
||
"texture": "textures/silu/WallBlock",
|
||
"spriteUuid": None,
|
||
"alpha": 255,
|
||
},
|
||
{
|
||
"name": "MapTile_Decor23",
|
||
"display": "装饰 素材23",
|
||
"layer": "border",
|
||
"tileKey": "Decor23",
|
||
"texture": "textures/silu/Decor23",
|
||
"spriteUuid": None,
|
||
"alpha": 255,
|
||
},
|
||
]
|
||
|
||
|
||
def uid() -> str:
|
||
return str(uuid.uuid4())
|
||
|
||
|
||
def vec3(x: float, y: float, z: float = 0) -> dict:
|
||
return {"__type__": "cc.Vec3", "x": x, "y": y, "z": z}
|
||
|
||
|
||
def quat() -> dict:
|
||
return {"__type__": "cc.Quat", "x": 0, "y": 0, "z": 0, "w": 1}
|
||
|
||
|
||
def file_id() -> str:
|
||
chars = string.ascii_letters + string.digits
|
||
return "".join(random.choices(chars, k=22))
|
||
|
||
|
||
def read_sprite_uuid_from_meta(project: Path, texture_path: str) -> str | None:
|
||
meta_path = project / "assets/resources" / f"{texture_path}.png.meta"
|
||
if not meta_path.is_file():
|
||
return None
|
||
try:
|
||
meta = json.loads(meta_path.read_text(encoding="utf-8"))
|
||
base = meta.get("uuid")
|
||
if base:
|
||
return f"{base}@f9941"
|
||
except Exception:
|
||
pass
|
||
return None
|
||
|
||
|
||
def build_tile_prefab(tile: dict) -> list:
|
||
objs: list[dict] = []
|
||
root_id = 1
|
||
|
||
objs.append(
|
||
{
|
||
"__type__": "cc.Prefab",
|
||
"_name": tile["name"],
|
||
"_objFlags": 0,
|
||
"_native": "",
|
||
"data": {"__id__": root_id},
|
||
"optimizationPolicy": 0,
|
||
"persistent": False,
|
||
}
|
||
)
|
||
objs.append(
|
||
{
|
||
"__type__": "cc.Node",
|
||
"_name": tile["name"],
|
||
"_objFlags": 0,
|
||
"_parent": None,
|
||
"_children": [],
|
||
"_active": True,
|
||
"_components": [],
|
||
"_prefab": {"__id__": 2},
|
||
"_lpos": vec3(0, 0, 0),
|
||
"_lrot": quat(),
|
||
"_lscale": vec3(1, 1, 1),
|
||
"_layer": LAYER_DEFAULT,
|
||
"_euler": vec3(0, 0, 0),
|
||
"_id": "",
|
||
}
|
||
)
|
||
objs.append(
|
||
{
|
||
"__type__": "cc.PrefabInfo",
|
||
"root": {"__id__": root_id},
|
||
"asset": {"__id__": 0},
|
||
"fileId": file_id(),
|
||
}
|
||
)
|
||
return objs
|
||
|
||
|
||
def write_meta(prefab_path: Path, prefab_uuid: str) -> None:
|
||
meta = {
|
||
"ver": "1.1.50",
|
||
"importer": "prefab",
|
||
"imported": True,
|
||
"uuid": prefab_uuid,
|
||
"files": [".json"],
|
||
"subMetas": {},
|
||
"userData": {"syncNodeName": prefab_path.stem},
|
||
}
|
||
prefab_path.with_suffix(".prefab.meta").write_text(
|
||
json.dumps(meta, indent=2), encoding="utf-8"
|
||
)
|
||
|
||
|
||
def main():
|
||
project = Path(__file__).resolve().parent.parent
|
||
out = project / "assets/resources/map-tiles"
|
||
out.mkdir(parents=True, exist_ok=True)
|
||
|
||
catalog = []
|
||
for tile in MAP_TILES:
|
||
sprite_uuid = tile.get("spriteUuid") or read_sprite_uuid_from_meta(
|
||
project, tile["texture"]
|
||
)
|
||
if not sprite_uuid:
|
||
sprite_uuid = "5625da25-9915-416f-be60-c6decb355672@f9941"
|
||
print(f" warn: {tile['name']} 使用 Baseblock 占位,请在编辑器导入 {tile['texture']}.png 后重烘焙")
|
||
|
||
p = out / f"{tile['name']}.prefab"
|
||
p.write_text(json.dumps(build_tile_prefab(tile), indent=2), encoding="utf-8")
|
||
write_meta(p, uid())
|
||
catalog.append(
|
||
{
|
||
"name": tile["name"],
|
||
"display": tile["display"],
|
||
"layer": tile["layer"],
|
||
"tileKey": tile["tileKey"],
|
||
"texture": tile["texture"],
|
||
"prefab": f"map-tiles/{tile['name']}",
|
||
}
|
||
)
|
||
print(f" baked {tile['name']}")
|
||
|
||
(out / "_palette.json").write_text(
|
||
json.dumps({"tiles": catalog}, indent=2, ensure_ascii=False), encoding="utf-8"
|
||
)
|
||
print(f"Palette catalog -> {out / '_palette.json'}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|