mk_bezier_animation/assets/BezierCurveAnimation.ts

188 lines
6.3 KiB
TypeScript
Raw Permalink Normal View History

2022-07-15 18:23:35 +08:00
import { _decorator, Component } from 'cc';
2022-07-13 18:35:31 +08:00
import * as cc from 'cc';
import BezierCurve from './BezierCurve';
2022-07-16 01:54:43 +08:00
const { ccclass, property, help } = _decorator;
2022-07-13 18:35:31 +08:00
/** 缓动枚举 */
let easingEnum = {};
{
let tempN = 0;
for (let kS in cc.easing) {
2022-07-15 18:23:35 +08:00
if (Object.prototype.hasOwnProperty.call(cc.easing, kS)) {
easingEnum[kS] = tempN;
easingEnum[tempN] = kS;
tempN++;
}
2022-07-13 18:35:31 +08:00
}
}
/** 缓动单元 */
@ccclass('BezierCurveAnimationTweenUnit')
class BezierCurveAnimationTweenUnit {
/* --------------- 属性 --------------- */
/** 自定义缓动曲线 */
@property({ displayName: '自定义缓动曲线' })
customCurveB = false;
/** 缓动曲线 */
@property({
displayName: '缓动曲线',
type: cc.Enum(easingEnum),
visible: function (this: BezierCurveAnimationTweenUnit) {
return !this.customCurveB;
}
})
easing = 0;
/** 缓动控制点 */
@property({
displayName: '控制点',
type: [cc.Vec3],
visible: function (this: BezierCurveAnimationTweenUnit) {
return this.customCurveB;
}
})
controlPointV3S: cc.Vec3[] = [];
/** 时间(秒) */
@property({ displayName: '时间(秒)' })
timeSN = 0;
}
/** 贝塞尔曲线通用动画组件 */
@ccclass('BezierCurveAnimation')
2022-07-16 01:54:43 +08:00
@help('https://www.desmos.com/calculator/cahqdxeshd?lang=zh-CN')
2022-07-13 18:35:31 +08:00
export class BezierCurveAnimation extends Component {
/* --------------- 属性 --------------- */
/** 缓动单元 */
@property({ displayName: '缓动单元', type: [BezierCurveAnimationTweenUnit] })
2022-07-15 18:23:35 +08:00
tweenUnitAS: BezierCurveAnimationTweenUnit[] = [];
2022-07-13 18:35:31 +08:00
/** 缓动切换事件 */
2022-07-15 18:23:35 +08:00
@property({ displayName: '缓动切换事件', tooltip: '(当前缓动下标_indexN)', type: [cc.EventHandler] })
tweenSwitchEventAS: cc.EventHandler[] = [];
2022-07-13 18:35:31 +08:00
/** 更新事件 */
2022-07-14 17:42:02 +08:00
@property({
displayName: '更新事件',
2022-07-16 20:33:24 +08:00
tooltip: '(当前缓动曲线Y_yN, 当前缓动下标_indexN, 总曲线Y_yN)',
2022-07-15 18:23:35 +08:00
type: [cc.EventHandler]
2022-07-14 17:42:02 +08:00
})
2022-07-15 18:23:35 +08:00
updateEventAS: cc.EventHandler[] = [];
2022-07-13 18:35:31 +08:00
/** 结束事件 */
2022-07-15 18:23:35 +08:00
@property({ displayName: '结束事件', type: [cc.EventHandler] })
endEventAS: cc.EventHandler[] = [];
2022-07-13 18:35:31 +08:00
/* --------------- private --------------- */
2022-07-15 18:23:35 +08:00
/* ------------------------------- 功能 ------------------------------- */
/** 触发事件 */
emit(eventKey_: keyof BezierCurveAnimation, ...argsAS_: any[]): void {
let eventAS = this[eventKey_] as cc.EventHandler[];
if (!eventAS) {
return;
}
eventAS.forEach((v) => {
v.emit(argsAS_);
});
}
2022-07-14 17:42:02 +08:00
/**
*
* @param startIndexN_
* @param endIndexN_
* @returns
*/
2022-07-16 04:02:04 +08:00
startTween(startIndexN_?: number): cc.Tween<any>;
startTween(tweenNS_?: number[]): cc.Tween<any>;
startTween(args_?: number | number[]): cc.Tween<any> {
/** 缓动队列 */
2022-07-15 18:23:35 +08:00
let tweenUnitAs = this.tweenUnitAS;
2022-07-16 04:02:04 +08:00
// 获取缓动队列
if (args_ !== undefined) {
if (typeof args_ === 'number') {
tweenUnitAs = tweenUnitAs.slice(args_, 1);
} else {
tweenUnitAs = [];
args_.forEach((vN) => {
tweenUnitAs.push(this.tweenUnitAS[vN]);
});
}
tweenUnitAs = tweenUnitAs.filter((v) => Boolean(v));
2022-07-14 17:42:02 +08:00
}
2022-07-16 04:02:04 +08:00
if (!tweenUnitAs.length) {
return;
}
2022-07-13 18:35:31 +08:00
/** 总时间(秒) */
2022-07-14 17:42:02 +08:00
let totalTimeSN = tweenUnitAs.reduce((preValue, currValue) => preValue + currValue.timeSN, 0);
2022-07-13 18:35:31 +08:00
/** 时间占比 */
let timeRatioNs: number[] = [];
{
let currN = 0;
2022-07-14 17:42:02 +08:00
tweenUnitAs.forEach((v, kN) => {
2022-07-13 18:35:31 +08:00
let ratioN = v.timeSN / totalTimeSN;
currN += ratioN;
timeRatioNs.push(currN);
});
}
/** 曲线函数 */
2022-07-14 17:42:02 +08:00
let curveFS = tweenUnitAs.map((v) => {
2022-07-13 18:35:31 +08:00
if (v.customCurveB) {
let curve = new BezierCurve(v.controlPointV3S);
2022-07-14 17:42:02 +08:00
return (kN: number) => {
return curve.point(kN).y;
};
2022-07-13 18:35:31 +08:00
} else {
return cc.easing[easingEnum[v.easing]].bind(cc.easing) as (kN: number) => number;
}
});
/** 上次缓动下标 */
let lastTweenIndexN = 0;
/** 缓动对象 */
let tweenTarget = { valueN: 0 };
/** 缓动 */
let tween = cc
.tween(tweenTarget)
.to(
totalTimeSN,
{
valueN: 1
},
{
onUpdate: (target: typeof tweenTarget, ratioN: number) => {
/** 当前缓动下标 */
let tweenIndexN = timeRatioNs.findIndex((vN) => ratioN <= vN);
if (tweenIndexN === -1) {
return;
}
/** 上个时间占比 */
let lastTimeRatioN = tweenIndexN ? timeRatioNs[tweenIndexN - 1] : 0;
/** 当前时间范围 */
let timeRangeN = timeRatioNs[tweenIndexN] - lastTimeRatioN;
/** 曲线位置 */
let posN = (ratioN - lastTimeRatioN) / timeRangeN;
2022-07-16 20:33:24 +08:00
/** 当前曲线 Y */
let currCurveYN = curveFS[tweenIndexN](posN);
/** 总曲线 Y */
let totalCurveYN = currCurveYN * timeRangeN + lastTimeRatioN;
2022-07-13 18:35:31 +08:00
// 缓动切换事件触发
if (lastTweenIndexN !== tweenIndexN) {
2022-07-15 18:23:35 +08:00
this.emit('tweenSwitchEventAS', lastTweenIndexN);
2022-07-13 18:35:31 +08:00
}
// 更新事件触发
2022-07-16 20:33:24 +08:00
this.emit('updateEventAS', currCurveYN, tweenIndexN, totalCurveYN);
2022-07-13 18:35:31 +08:00
// 更新缓动下标
lastTweenIndexN = tweenIndexN;
}
}
)
.call(() => {
// 结束事件触发
2022-07-15 18:23:35 +08:00
this.emit('endEventAS');
2022-07-13 18:35:31 +08:00
})
.start();
return tween;
}
}