cocos-farm/tools/generate_crop_foot_anchors.py

75 lines
2.5 KiB
Python

#!/usr/bin/env python3
"""Generate crop root anchors from transparent PNG bounds."""
from __future__ import annotations
from pathlib import Path
from PIL import Image
ROOT = Path(__file__).resolve().parents[1]
CROP_DIR = ROOT / "CocosFarm" / "assets" / "resources" / "textures" / "stage1"
OUTPUT = ROOT / "CocosFarm" / "assets" / "scripts" / "mock" / "Stage1CropFootAnchorMock.ts"
def fmt(value: float) -> str:
if value == int(value):
return str(int(value))
return str(round(value, 3)).rstrip("0").rstrip(".")
def main() -> int:
anchors: dict[str, tuple[float, float]] = {}
for path in sorted(CROP_DIR.glob("Crop_*.png")):
image = Image.open(path).convert("RGBA")
alpha = image.getchannel("A")
bounds = alpha.getbbox()
if bounds is None:
continue
left, top, right, bottom = bounds
width, height = image.size
if "Seed" in path.stem:
foot_x = (left + right) / 2 - width / 2
foot_y = height / 2 - bottom
else:
visible_height = bottom - top
root_band_height = max(4, round(visible_height * 0.14))
root_top = max(top, bottom - root_band_height)
root_bounds = alpha.crop((0, root_top, width, bottom)).getbbox()
if root_bounds is None:
continue
root_left, root_band_top, root_right, root_band_bottom = root_bounds
root_top_world = root_top + root_band_top
root_bottom_world = root_top + root_band_bottom
foot_x = (root_left + root_right) / 2 - width / 2
foot_y = height / 2 - (root_top_world + root_bottom_world) / 2
anchors[path.stem] = (foot_x, foot_y)
lines = [
"export interface Stage1CropFootAnchor {",
" footX: number;",
" footY: number;",
"}",
"",
"export const STAGE1_CROP_FOOT_ANCHORS: Record<string, Stage1CropFootAnchor> = {",
]
for index, (asset_id, (foot_x, foot_y)) in enumerate(anchors.items()):
suffix = "," if index < len(anchors) - 1 else ""
lines.extend(
[
f' "{asset_id}": {{',
f' "footX": {fmt(foot_x)},',
f' "footY": {fmt(foot_y)}',
f" }}{suffix}",
]
)
lines.append("};")
OUTPUT.write_text("\n".join(lines) + "\n", encoding="utf-8")
print(f"wrote {OUTPUT} ({len(anchors)} anchors)")
return 0
if __name__ == "__main__":
raise SystemExit(main())