import { TweenEasing } from "./TweenEasing"; const { ccclass, property, executeInEditMode, playOnFocus } = cc._decorator; /** * 缓动数据 * @author 薛鸿潇 */ enum ActionType{ Act_Absolute, Act_relative, } @ccclass("PropsData") export class PropsData { @property({ displayName: "坐标" }) public position: cc.Vec2 = cc.Vec2.ZERO; @property({ displayName: "旋转" }) public angle: number = 0; @property({ displayName: "缩放" }) public scale: number = 1; @property({displayName: "显示隐藏", tooltip: '打勾是显示'}) public active: boolean = true; } /** * 缓动数据 * @author 薛鸿潇 */ @ccclass("TweenData") export class TweenData { @property({ displayName: "属性数据", type: PropsData }) public propsData: PropsData = new PropsData(); @property({ displayName: "持续时间", tooltip: '单位:秒' }) public duration: number = 0.3; @property({ displayName: "延迟时间", tooltip: '单位:秒' }) public delay: number = 0; @property({ displayName: "是否为差值" }) public isOffset: boolean = false; @property({ displayName: '完成回调', tooltip: "缓动完成时触发", type: cc.Component.EventHandler }) public onComplete: cc.Component.EventHandler[] = []; @property({ displayName: '开始回调', tooltip: "缓动启动时触发", type: cc.Component.EventHandler }) public onStart: cc.Component.EventHandler[] = []; @property({ displayName: '过程回调', tooltip: "缓动更新时触发", type: cc.Component.EventHandler }) public onUpdate: cc.Component.EventHandler[] = []; } /** * 缓动组件,目前只支持节点的三个基础属性 * @author 薛鸿潇 */ @ccclass @executeInEditMode() @playOnFocus() export class UITween extends cc.Component { @property({ displayName: "节点初始属性", type: PropsData }) public fromData: PropsData = new PropsData(); @property({ displayName: "节点目标属性", type: TweenData }) public targetData: TweenData[] = []; @property({ displayName: '缓动节点', tooltip: "要播放缓动动画的目标,不填则是当前节点", type: cc.Node }) public target: cc.Node = null; @property({ displayName: "缓动效果", type: cc.Enum(TweenEasing) }) public tweenEasing: TweenEasing = TweenEasing.sineInOut; @property({ displayName: '执行次数', tooltip: "为0则一直重复执行" }) public repeat: number = 1; @property({ displayName: "单次完成回调", tooltip: '单次缓动序列执行完毕时触发', type: cc.Component.EventHandler }) public onOneRepeatComplete: cc.Component.EventHandler = new cc.Component.EventHandler(); @property({ displayName: "自动播放" }) public playOnLoad: boolean = true; @property({displayName: "绝对移动or相对移动", type: cc.Enum(ActionType)}) public actType: ActionType = ActionType.Act_Absolute; @property({displayName:'是否设置起始位置为屏幕旁边按屏幕加节点尺寸的一半'}) public isSetSuitStartPos: boolean = false; @property({displayName: '是否延时设置初始属性'}) public isDelaySetOrigin = null; private _edit_play: boolean = false; @property({ displayName: "编辑器预览" }) get edit_play(): boolean { if (this._edit_play && !this.edit_playing) { this.edit_playing = true; this.play(); } return this._edit_play; } set edit_play(v: boolean) { this._edit_play = v; if (this.target && v) { cc.Tween.stopAllByTarget(this.target); } if (!v) this.edit_playing = false; } private resetProperty: boolean = false; @property({displayName: '重置基础属性'}) get reset_property():boolean{ if(this.resetProperty) { this.fromData.position = cc.v2(this.node.position.x, this.node.position.y); this.fromData.angle = this.node.angle; this.fromData.scale = this.node.scale; for(let i = 0; i != this.targetData.length; ++i) { let target = this.targetData[i]; target.propsData.position = cc.v2(this.node.position.x, this.node.position.y); target.propsData.angle = this.node.angle; target.propsData.scale = this.node.scale; } this.resetProperty = false; } return this.resetProperty; } set reset_property(v){ this.resetProperty = v; } /** 编辑器是否正在播放 */ private edit_playing = false; public start() { !this.target && (this.target = this.node); this.target = this.target || this.node; this.currentRepeat = this.repeat; if (CC_EDITOR) { this._edit_play && this.play(); } else { this.playOnLoad && this.play(); } } private t: cc.Tween; /** 剩余播放次数 */ private currentRepeat: number; public play() { if (CC_EDITOR && !this.edit_playing) return; if (this.repeat == 0) { this.t = cc.tween(this.target); this.readyPlay(); this.t = this.t.call(this.play.bind(this)); this.t.start(); } else if (this.currentRepeat) { this.t = cc.tween(this.target); this.readyPlay(); this.t = this.t.call(this.play.bind(this)); this.currentRepeat--; this.t.start(); } else { this.t = null; this.currentRepeat = this.repeat; this.edit_play = false; } } public readyPlay() { let self = this; if (this.fromData) { if(this.isSetSuitStartPos) { if(this.fromData.position.x >0) { this.fromData.position.x = cc.winSize.width / 2 + this.target.getContentSize().width/2; }else{ this.fromData.position.x = -cc.winSize.width / 2 - this.target.getContentSize().width/2; } } this.node.setPosition(this.fromData.position.clone()); this.node.scale = this.fromData.scale; this.node.angle = this.fromData.angle; this.node.active = this.fromData.active; } if (this.targetData.length) { for (let i = 0; i < this.targetData.length; i++) { const targetData = this.targetData[i]; if (targetData.delay != 0) { this.t = this.t.delay(targetData.delay); } if(targetData.propsData.active) { this.t = this.t.call(()=>{ this.node.active = true; }); }else{ this.t = this.t.call(()=>{ this.node.active = false; }); } let toData = { position: targetData.propsData.position, scale: targetData.propsData.scale, angle: targetData.propsData.angle, } if (targetData.isOffset) { toData.position = this.node.getPosition().add(targetData.propsData.position); toData.scale = this.node.scale + targetData.propsData.scale; toData.angle = this.node.angle + targetData.propsData.angle; } if(this.actType == ActionType.Act_Absolute) { this.t = this.t.to( targetData.duration, toData, { easing: TweenEasing[this.tweenEasing] as any, onComplete: (target: cc.Node) => { console.log("----------tweenComplete"); if(targetData.onComplete && targetData.onComplete.length > 0) { for(let i = 0; i != targetData.onComplete.length; ++i) { targetData.onComplete[i].emit([target]); } } //targetData.onComplete && targetData.onComplete.emit([target]); // this.edit_playing = false; // this._edit_play = false; }, onStart: (target: cc.Node) => { console.log("----------tweenStart"); //targetData.onStart && targetData.onStart.emit([target]) if(targetData.onStart && targetData.onStart.length > 0) { for(let i = 0; i != targetData.onStart.length; ++i) { targetData.onStart[i].emit([target]); } } }, onUpdate: (target: cc.Node, ratio: number) => { //targetData.onUpdate && targetData.onUpdate.emit([target, ratio]) if(targetData.onUpdate && targetData.onUpdate.length > 0) { for(let i = 0; i != targetData.onUpdate.length; ++i) { targetData.onUpdate[i].emit([target]); } } } } ); }else { this.t = this.t.by( targetData.duration, toData, { easing: TweenEasing[this.tweenEasing] as any, onComplete: (target: cc.Node) => { console.log("----------tweenComplete"); if(targetData.onComplete && targetData.onComplete.length > 0) { for(let i = 0; i != targetData.onComplete.length; ++i) { targetData.onComplete[i].emit([target]); } } //targetData.onComplete && targetData.onComplete.emit([target]); // this.edit_playing = false; // this._edit_play = false; }, onStart: (target: cc.Node) => { console.log("----------tweenStart"); //targetData.onStart && targetData.onStart.emit([target]) if(targetData.onStart && targetData.onStart.length > 0) { for(let i = 0; i != targetData.onStart.length; ++i) { targetData.onStart[i].emit([target]); } } }, onUpdate: (target: cc.Node, ratio: number) => { //targetData.onUpdate && targetData.onUpdate.emit([target, ratio]) if(targetData.onUpdate && targetData.onUpdate.length > 0) { for(let i = 0; i != targetData.onUpdate.length; ++i) { targetData.onUpdate[i].emit([target]); } } } } ); } } } if (this.onOneRepeatComplete) { this.t = this.t.call(() => { self.onOneRepeatComplete.emit([this, this.t]) }); } } }