//********************* // create by 流云 // time: 2025.03.10 // desc: //********************* import { _decorator, Camera, CCFloat, Component, director, Node, Tween, tween, UIOpacity, Vec3 } from 'cc'; import { MoveCamera } from './MoveCamera'; const { ccclass, property } = _decorator; /** * 目标动画(可实现路径动画) * 编辑子节点为动画路径节点,子节点顺序为动画路径顺序 * 配置pathTime为每个路径节点对应的时间 * 例如:我要实现一个物体先移动到A,然后从A移动到B,然后从B移动到C的动画 * 实现步骤如下: * 1先创建3个空物体为本组件的子节点,分别命名为A、B、C * 2然后编辑3个空物体的transform属性,分别设置为A、B、C的位置 * 3将pathTime长度设置为3,值分别为1、0.5、2 * 4将playOnEnable设置为true * (示例只写了position,缩放和旋转也支持的) */ @ccclass('TargetTween') export class TargetTween extends Component { @property({ type: Node, tooltip: "动画目标节点" }) targetNode: Node = null; @property({ type: CCFloat, tooltip: "路径节点对应的时间" }) pathTime: number[] = []; @property({ tooltip: "显示时播放" }) playOnEnable: boolean = true; @property({ tooltip: "循环" }) Loop: boolean = false; private _onTweenUpdateCallback: Function = null; protected onLoad(): void { if (!this.targetNode) this.targetNode = this.node; } protected onEnable(): void { this.startPlay(); } /** * 开始播放路径动画 * @param onUpdateCallback 播放时的每帧回调 * @param onCompleteCallback 播放完成的回调 */ async startPlay(onUpdateCallback?: Function, onCompleteCallback?: Function) { this._onTweenUpdateCallback = onUpdateCallback; if (!this.node || !this.node.isValid) return; for (let i = 0; i < this.node.children.length; i++) { if (i < this.node.children.length) { let n = this.node.children[i]; if (n.getComponent(MoveCamera)) { await this.playCameraTween(n); } else { if (i < this.pathTime.length) { let t = this.pathTime[i]; await this.playTween(n, t); } } } } if (this.Loop && this.node && this.node.isValid) { this.startPlay(onUpdateCallback, onCompleteCallback); } else { if (this.targetNode && this.targetNode.active && onCompleteCallback) onCompleteCallback(); } } stopPlay() { this._onTweenUpdateCallback = null; Tween.stopAllByTarget(this.targetNode); } private playTween(target: Node, time: number) { return new Promise((resolve) => { tween(this.targetNode).to(time, { worldPosition: target.worldPosition, scale: target.scale, rotation: target.rotation }, { onUpdate: () => { if (this._onTweenUpdateCallback) this._onTweenUpdateCallback(); } }).call(() => { resolve(null); }).start(); let op1 = target.getComponent(UIOpacity); let op2 = this.targetNode.getComponent(UIOpacity); if (op1 && op2) { tween(op2).to(time, { opacity: op1.opacity }).start(); } }); } private playCameraTween(target: Node) { return new Promise((resolve) => { target.getComponent(MoveCamera).startMove(() => { resolve(null); }) }) } }