import { _decorator, Component, Node, tween, Vec3, Sprite, UITransform } from "cc"; const { ccclass, property } = _decorator; @ccclass("HintManager") export class HintManager extends Component { @property(Node) handNode: Node | null = null; // 编辑器里拖一只手的 sprite 节点 private runningTween: any = null; // 传入 getHint 的结果 showHint(hint: any, getPos: (r: number, c: number) => Vec3) { if (!this.handNode) return; // 清理之前的动画 if (this.runningTween) { this.runningTween.stop(); this.runningTween = null; } if (!hint.from || !hint.dir || hint.steps == null) return; const { from, dir, steps } = hint; const dr = dir.dr; const dc = dir.dc; // 生成路径格子(起点 + dir * step) const pathCells: { r: number; c: number }[] = []; for (let s = 0; s <= steps; s++) { pathCells.push({ r: from.r + dr * s, c: from.c + dc * s }); } // 转换成 UI 坐标 const positions: Vec3[] = pathCells.map(cell => getPos(cell.r, cell.c)); const startPos = positions[0]; this.handNode.active = true; this.handNode.setSiblingIndex(this.handNode.parent.children.length - 1); this.handNode.setPosition(startPos); // 构建单向滑动动画(格子之间平均时间) const durationPerCell = 1 / steps; let tw = tween(this.handNode); for (let i = 1; i < positions.length; i++) { tw = tw.to(durationPerCell, { position: positions[i] }); } // 到终点瞬间回起点 tw = tw.call(() => this.handNode.setPosition(startPos)); // 重复 3 次 this.runningTween = tween(this.handNode) .repeat(3, tw) .call(() => { this.handNode.active = false; this.runningTween = null; }) .start(); } cancelHint() { if (this.runningTween) { try { this.runningTween.stop(); } catch (e) { console.warn("停止手势动画失败", e); } this.runningTween = null; } if (this.handNode) { this.handNode.active = false; } } }