You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
3.6 KiB
108 lines
3.6 KiB
|
1 week ago
|
//*********************
|
||
|
|
// 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);
|
||
|
|
})
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|