"""把 UI 动效预设编译成 Cocos TypeScript(cc.tween)。 纯本地、无需 API。生成一个 TweenPresets.ts,运行时按 presetId 调用即可。 """ import os PRESETS = { "scale_bounce": """ scale_bounce(node: Node, p: any = {}) { const s = node.scale.clone(); return tween(node) .to(0.09, { scale: new Vec3(s.x * 0.9, s.y * 0.9, 1) }) .to(0.12, { scale: new Vec3(s.x * 1.05, s.y * 1.05, 1) }, { easing: 'backOut' }) .to(0.08, { scale: s }); }""", "elastic_in": """ elastic_in(node: Node, p: any = {}) { node.setScale(0, 0, 1); const uo = node.getComponent(UIOpacity); if (uo) uo.opacity = 0; return tween(node) .to(0.4, { scale: new Vec3(1, 1, 1) }, { easing: 'elasticOut' }) .call(() => { if (uo) uo.opacity = 255; }); }""", "fade_slide_in": """ fade_slide_in(node: Node, p: any = {}) { const dy = p.dy ?? 40; const end = node.position.clone(); node.setPosition(end.x, end.y - dy, end.z); const uo = node.getComponent(UIOpacity); if (uo) { uo.opacity = 0; tween(uo).to(0.3, { opacity: 255 }).start(); } return tween(node).to(0.3, { position: end }, { easing: 'cubicOut' }); }""", "number_roll": """ number_roll(node: Node, p: any = {}) { const label = node.getComponent(Label)!; const from = p.from ?? 0, to = p.to ?? 0, dur = p.dur ?? 0.8; const o = { v: from }; return tween(o).to(dur, { v: to }, { easing: 'cubicOut', onUpdate: () => { label.string = Math.floor(o.v).toString(); }, }); }""", "pulse": """ pulse(node: Node, p: any = {}) { const s = node.scale.clone(); return tween(node).repeatForever( tween(node) .to(0.6, { scale: new Vec3(s.x * 1.06, s.y * 1.06, 1) }, { easing: 'sineInOut' }) .to(0.6, { scale: s }, { easing: 'sineInOut' }) ); }""", } HEADER = """// 自动生成 by anim_studio —— UI 动效预设库 // 用法: TweenPresets.play('scale_bounce', node, { ... }).start(); import { tween, Tween, Node, Vec3, UIOpacity, Label } from 'cc'; class _TweenPresets { play(id: string, node: Node, p: any = {}): Tween { const fn = (this as any)[id]; if (!fn) { console.warn('[TweenPresets] 未知预设: ' + id); return tween(node); } return fn.call(this, node, p); } """ FOOTER = "}\n\nexport const TweenPresets = new _TweenPresets();\n" def build_tweens(used_presets, out_dir): """生成 TweenPresets.ts。used_presets 为 manifest 用到的预设名列表(去重)。""" # 总是输出全部预设库(多几个不碍事),并校验用到的是否都存在 missing = [p for p in used_presets if p not in PRESETS] body = "\n\n".join(PRESETS[k] for k in PRESETS) code = HEADER + "\n" + body + "\n" + FOOTER os.makedirs(out_dir, exist_ok=True) path = os.path.join(out_dir, "TweenPresets.ts") with open(path, "w", encoding="utf-8") as f: f.write(code) return path, missing