mk_bezier_animation/assets/BezierCurveAnimation.ts
2022-07-13 18:35:31 +08:00

141 lines
4.9 KiB
TypeScript

import { _decorator, Component, Node } from 'cc';
import * as cc from 'cc';
import { EDITOR } from 'cc/env';
import BezierCurve from './BezierCurve';
const { ccclass, property } = _decorator;
/** 缓动枚举 */
let easingEnum = {};
{
let tempN = 0;
for (let kS in cc.easing) {
easingEnum[kS] = tempN;
easingEnum[tempN] = kS;
tempN++;
}
}
/** 缓动单元 */
@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')
export class BezierCurveAnimation extends Component {
/* --------------- 属性 --------------- */
/** 缓动单元 */
@property({ displayName: '缓动单元', type: [BezierCurveAnimationTweenUnit] })
tweenUnitAs: BezierCurveAnimationTweenUnit[] = [];
/** 缓动切换事件 */
@property({ displayName: '缓动切换事件', tooltip: '(当前缓动下标_indexN)', type: cc.EventHandler })
tweenSwitchEvent = new cc.EventHandler();
/** 更新事件 */
@property({ displayName: '更新事件', tooltip: '(曲线Y_yN)', type: cc.EventHandler })
updateEvent = new cc.EventHandler();
/** 结束事件 */
@property({ displayName: '结束事件', type: cc.EventHandler })
endEvent = new cc.EventHandler();
/* --------------- private --------------- */
/* ------------------------------- segmentation ------------------------------- */
/** 开始缓动 */
startTween(): cc.Tween<any> {
/** 总时间(秒) */
let totalTimeSN = this.tweenUnitAs.reduce((preValue, currValue) => preValue + currValue.timeSN, 0);
/** 时间占比 */
let timeRatioNs: number[] = [];
{
let currN = 0;
this.tweenUnitAs.forEach((v, kN) => {
let ratioN = v.timeSN / totalTimeSN;
currN += ratioN;
timeRatioNs.push(currN);
});
}
/** 曲线函数 */
let curveFS = this.tweenUnitAs.map((v) => {
if (v.customCurveB) {
let curve = new BezierCurve(v.controlPointV3S);
return curve.point.bind(curve) as (kN: number) => number;
} 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;
/** 曲线位置 */
let yN = curveFS[tweenIndexN](posN) * timeRangeN + lastTimeRatioN;
// 缓动切换事件触发
if (lastTweenIndexN !== tweenIndexN) {
this.tweenSwitchEvent?.emit([lastTweenIndexN]);
}
// 更新事件触发
this.updateEvent?.emit([yN]);
// 更新缓动下标
lastTweenIndexN = tweenIndexN;
}
}
)
.call(() => {
// 结束事件触发
this.endEvent?.emit([]);
})
.start();
return tween;
}
}