tween_builder.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. """把 UI 动效预设编译成 Cocos TypeScript(cc.tween)。
  2. 纯本地、无需 API。生成一个 TweenPresets.ts,运行时按 presetId 调用即可。
  3. """
  4. import os
  5. PRESETS = {
  6. "scale_bounce": """ scale_bounce(node: Node, p: any = {}) {
  7. const s = node.scale.clone();
  8. return tween(node)
  9. .to(0.09, { scale: new Vec3(s.x * 0.9, s.y * 0.9, 1) })
  10. .to(0.12, { scale: new Vec3(s.x * 1.05, s.y * 1.05, 1) }, { easing: 'backOut' })
  11. .to(0.08, { scale: s });
  12. }""",
  13. "elastic_in": """ elastic_in(node: Node, p: any = {}) {
  14. node.setScale(0, 0, 1);
  15. const uo = node.getComponent(UIOpacity); if (uo) uo.opacity = 0;
  16. return tween(node)
  17. .to(0.4, { scale: new Vec3(1, 1, 1) }, { easing: 'elasticOut' })
  18. .call(() => { if (uo) uo.opacity = 255; });
  19. }""",
  20. "fade_slide_in": """ fade_slide_in(node: Node, p: any = {}) {
  21. const dy = p.dy ?? 40;
  22. const end = node.position.clone();
  23. node.setPosition(end.x, end.y - dy, end.z);
  24. const uo = node.getComponent(UIOpacity);
  25. if (uo) { uo.opacity = 0; tween(uo).to(0.3, { opacity: 255 }).start(); }
  26. return tween(node).to(0.3, { position: end }, { easing: 'cubicOut' });
  27. }""",
  28. "number_roll": """ number_roll(node: Node, p: any = {}) {
  29. const label = node.getComponent(Label)!;
  30. const from = p.from ?? 0, to = p.to ?? 0, dur = p.dur ?? 0.8;
  31. const o = { v: from };
  32. return tween(o).to(dur, { v: to }, {
  33. easing: 'cubicOut',
  34. onUpdate: () => { label.string = Math.floor(o.v).toString(); },
  35. });
  36. }""",
  37. "pulse": """ pulse(node: Node, p: any = {}) {
  38. const s = node.scale.clone();
  39. return tween(node).repeatForever(
  40. tween(node)
  41. .to(0.6, { scale: new Vec3(s.x * 1.06, s.y * 1.06, 1) }, { easing: 'sineInOut' })
  42. .to(0.6, { scale: s }, { easing: 'sineInOut' })
  43. );
  44. }""",
  45. }
  46. HEADER = """// 自动生成 by anim_studio —— UI 动效预设库
  47. // 用法: TweenPresets.play('scale_bounce', node, { ... }).start();
  48. import { tween, Tween, Node, Vec3, UIOpacity, Label } from 'cc';
  49. class _TweenPresets {
  50. play(id: string, node: Node, p: any = {}): Tween<any> {
  51. const fn = (this as any)[id];
  52. if (!fn) { console.warn('[TweenPresets] 未知预设: ' + id); return tween(node); }
  53. return fn.call(this, node, p);
  54. }
  55. """
  56. FOOTER = "}\n\nexport const TweenPresets = new _TweenPresets();\n"
  57. def build_tweens(used_presets, out_dir):
  58. """生成 TweenPresets.ts。used_presets 为 manifest 用到的预设名列表(去重)。"""
  59. # 总是输出全部预设库(多几个不碍事),并校验用到的是否都存在
  60. missing = [p for p in used_presets if p not in PRESETS]
  61. body = "\n\n".join(PRESETS[k] for k in PRESETS)
  62. code = HEADER + "\n" + body + "\n" + FOOTER
  63. os.makedirs(out_dir, exist_ok=True)
  64. path = os.path.join(out_dir, "TweenPresets.ts")
  65. with open(path, "w", encoding="utf-8") as f:
  66. f.write(code)
  67. return path, missing