抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

基本原理

概述

缓动的基本原理很简单,就是设置一个初值和终值,在每帧更新的时候根据特定的缓动函数算出对应的中间值并插值。

本工具类分为 4 个部分:缓动工具类、缓动辅助类、缓动核心类、缓动时间类。同时,本工具提供链式调用,方便进行多个缓动动作的连续执行。

  1. 缓动工具类负责管理缓动的调用,以及一个作用域所有的缓动。

  2. 缓动辅助类负责管理单个缓动的初始化,同时也是链式调用的核心类。

  3. 缓动核心类负责管理具体的缓动逻辑,所以缓动都是通过该类执行。

  4. 缓动时间类负责管理缓动的更新调用,本项目托管到 Laya 的更新脚本上。

由于本类在设计之初是在 Laya 引擎运行,因此小部分代码依托 Laya 存在,使用的时候需要根据具体项目进行修改。

使用方法

所有的操作均从缓动工具类调用,但首先在运行之前要执行 TweenUtil.start()方法来初始化整个缓动工具的更新逻辑。

to 和 from 方法表示两个不同的缓动类型,to 为从当前状态到目标状态,from 为从目标状态到当前状态。这两个方法都会返回一个 subTween 对象,我们可以以这个 subTween 对象进行链式调用,以点的方法重复调用 to、from 等方法。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let obj = { x: 0 };
TweenUtil.to(
obj,
{
x: 1,
},
100
)
.to(
{
x: 2,
},
100
)
.to(
{
x: 3,
},
200
);

此处执行了三个缓动,obj 的 x 值从 0 到 1 到 2 再到 3。三个缓动按照顺序执行一次。

同时,本项目也提供了循环执行缓动的功能,只需要在最后调用 loop() 方法,就可以对 loop 之前的所有步骤重复执行。另外,本项目也支持设置循环次数,只需要如下调用即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
let obj = { x: 0 };
TweenUtil.to(
obj,
{
x: 1,
},
100
)
.to(
{
x: 2,
},
100
)
.to(
{
x: 3,
},
200
)
.loop();

let obj2 = { x: 0 };
TweenUtil.to(
obj2,
{
x: 1,
},
100
)
.to(
{
x: 2,
},
100
)
.to(
{
x: 3,
},
200
)
.loop(3);

如果存在两个 loop,若前面的 loop 为无限循环,则后面的 loop 无法执行,若不是无限循环,则后面的 loop 会执行第一个 loop 到第二个 loop 之间的缓动行为,第一个 loop 之前的缓动行为全部舍弃。其他情况同理。

如果要清理缓动,有两种方法,一种是调用 TweenUtil.clear() 方法,传入一个缓动对象,则这个缓动对象会被清理,另一种是清理作用域上的所有缓动对象,调用 TweenUtil.clearAll() 方法,传入作用域,则该作用域上的所有缓动对象都会被清理。

特别注意,本项目目前不支持缓动对象池,因为有可能会出现引用 bug,因此需要缓动对象池的话请自行实现。

缓动工具类原理

本类内置 3 个变量 _tweenId ,_tweenDic , _tweenClock

  1. _tweenId 变量用于自增缓动 id,也是缓动对象字典中的唯一标识符,每个作用域对应一个缓动 id。
  2. _tweenDic 变量为缓动对象字典,用于存储缓动对象,结构为 { tweenId : SubTween[] } , key 为缓动 id,value 为缓动辅助类数组,保存该作用域上的所有缓动对象。
  3. _tweenClock 变量为缓动核心类对象,在缓动核心类中会调用它来获取缓动时间类

本类的核心方法 to 和 from 的原理相同,方法分为两个部分:

  1. 创建一个缓动辅助类对象,设置对象的目标并且调用对应 to/from 方法。
  2. 检查作用域的缓动 id,如果不存在,则初始化缓动 id,然后检查字典中是否存在对应 id 并把创建的对象保存到数组中,最后再返回这个对象。

清除缓动的原理则如下方详细代码所示。

缓动辅助类原理

本类内置 8 个变量 target , _listIndex , _tweenList , _tweening , _tweenObj , _tweenIndex , _loop , _limit

  1. target 变量如名字所示,就是缓动的目标对象。
  2. _listIndex 变量用于缓动列表的索引,主要是区别各个 loop 缓动动作组,只有调用 loop 的情况下会增加。
  3. _tweenList 变量用于保存缓动动作,是一个二维数组,第一维保存缓动动作组,第二维保存缓动动作序列。
  4. _tweening 变量用于判断当前是否正在缓动
  5. _tweenObj 变量保存本类当前实例化的缓动核心类对象
  6. _tweenIndex 变量用于缓动序列的索引
  7. _loop 变量用于判断是否开启循环
  8. _limit 变量用于保存缓动循环次数限制,是个一维数组

本类的核心方法 to 和 from 的原理相同,方法分为两个部分:

  1. 保存缓动参数到 _tweenList[ _listIndex ] 数组中
  2. 如果缓动未启动,则启动缓动

本类最关键的,就是启动缓动的逻辑,具体逻辑如下图所示

本类的启动缓动,实际上就是上一个缓动动作和下一个缓动动作的连接,具体的缓动执行和结束,还得看缓动核心类。

缓动核心类原理

本类内置 11 个变量 _target , _prop , _duration , _ease , _complete , _delay , _direction , _isDone , _time , _def , _isDelay

  1. _target 变量如名字所示是缓动的对象
  2. _prop 变量保存需要缓动的所有属性
  3. _duration 变量是缓动的持续时间
  4. _ease 变量为缓动函数,所有缓动属性都需要通过该函数进行插值
  5. _complete 变量为回调函数,在缓动结束后执行,主要是执行缓动辅助类中的 doTween
  6. _delay 变量是缓动延迟时间,在延迟时间结束后才会开始执行缓动
  7. _direction 变量用于区分 to 和 from
  8. _isDone 变量用于标记是否完成缓动
  9. _time 变量用于记录当前缓动执行时间
  10. _def 变量用于保存缓动对象的原始属性
  11. _isDelay 变量用于标记是否延迟执行缓动

本类的 to 和 from 方法也是初始化传入的缓动参数,并且把本类对象推到缓动时间类的遍历列表中。

本类最关键的就是缓动每一帧更新的逻辑,具体逻辑如下图所示

注意,缓动函数的传参格式为: 经过时间,起始值,结束值,总时长,返回值为 0 到 1 的之间的数值

缓动时间类原理

本类在当前示例中依托 Laya 更新,也可以自定义定时器来更新。
核心逻辑主要就是 update,遍历 _tweens ,先判断缓动核心对象是否结束缓动,结束缓动就移除,否则就执行 update 函数 ,传入 deltaTime 即 dt,单位为毫秒。

注意本类一般需要在整个项目中成为单例,不过本类并没有实现单例类,如果需要的话可自行实现。记得配合修改 TweenUtil.start 的内容。

代码

缓动工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
export default class TweenUtil {
public static _tweenId = 1;

public static _tweenDic = {};

private static _tweenClock: TweenClock;

/**
* 启动缓动工具类 本函数负责启动缓动时间类,函数体可根据需求自定义修改
*/
public static start() {
let scriptScene = new Laya.Scene3D();
Laya.stage.addChild(scriptScene);
this._tweenClock = scriptScene.addComponent(TweenClock);
}

public static getTweenClock() {
return this._tweenClock;
}

/**
* to缓动 同Laya.Tween.to
* @param target
* @param prop
* @param time
* @param ease
* @param delay
* @param callback
* @returns
*/
public static to(caller, target, prop, time, ease?, delay?, callback?) {
// console.log("缓动",target);
let subTween = new SubTween();
subTween.target = target;
subTween.to(prop, time, ease, delay, callback);
if (!caller.tweenId) {
caller.tweenId = this._tweenId++;
}
if (!this._tweenDic[caller.tweenId]) {
this._tweenDic[caller.tweenId] = [];
}

this._tweenDic[caller.tweenId].push(subTween);
return subTween;
}

/**
* from缓动 同Laya.Tween.to
* @param target
* @param prop
* @param time
* @param ease
* @param delay
* @param callback
* @returns
*/
public static from(caller, target, prop, time, ease?, delay?, callback?) {
let subTween = new SubTween();
subTween.target = target;
subTween.to(prop, time, ease, delay, callback);
if (!caller.tweenId) {
caller.tweenId = this._tweenId++;
}
if (!this.caller[caller.tweenId]) {
this.caller[caller.tweenId] = [];
}

this._tweenDic[caller.tweenId].push(subTween);
return subTween;
}

/**
* 清除目标缓动
* @param tweenObj
*/
public static clear(tweenObj: SubTween) {
tweenObj.clear();
}

/**
* 清除目标节点所有缓动
* @param target
*/
public static clearAll(caller) {
// console.log("清除", caller)
if (!this._tweenDic[caller.tweenId]) return;
let len = this._tweenDic[caller.tweenId].length;
for (let i = 0; i < len; i++) {
(this._tweenDic[caller.tweenId][i] as SubTween).clear();
}

this._tweenDic[caller.tweenId] = [];
}
}

缓动辅助类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
export class SubTween {
/** 目标节点 */
public target;
/** 缓动列表索引 */
private _listIndex = 0;
/** 缓动列表 */
private _tweenList;
/** 是否正在缓动 */
private _tweening = false;
/** 缓动对象 */
private _tweenObj: TweenCore;
/** 缓动索引 */
private _tweenIndex = 0;
/** 是否循环 */
private _loop = false;
/** 缓动循环次数限制列表 */
private _limit: number[] = [];

/**
* 缓动 从现在属性到目标属性
* @param prop
* @param time
* @param ease
* @param delay
* @param callback
* @returns
*/
public to(prop, time, ease?, delay?, callback?) {
if (!this._tweenList) {
this._tweenList = [];
}
if (!this._tweenList[this._listIndex]) {
this._tweenList[this._listIndex] = [];
}
this._tweenList[this._listIndex].push({
prop: prop,
time: time,
ease: ease,
delay: delay,
callback: callback,
type: 0,
});
this.startTween();
return this;
}

/**
* 缓动 从目标属性到现在属性
* @param prop
* @param time
* @param ease
* @param delay
* @param callback
* @returns
*/
public from(prop, time, ease?, delay?, callback?) {
if (!this._tweenList) {
this._tweenList = [];
}
if (!this._tweenList[this._listIndex]) {
this._tweenList[this._listIndex] = [];
}
this._tweenList[this._listIndex].push({
prop: prop,
time: time,
ease: ease,
delay: delay,
callback: callback,
type: 1,
});
this.startTween();
return this;
}

/**
* 循环前面所有的动作
* @param 循环次数 不填或者0为无限循环 只有在非无限循环的情况下可以执行本次loop后面的缓动
*/
public loop(limit = 0) {
this._loop = true;
this._limit[this._listIndex] = limit - 1;
this._listIndex++;
return this;
}

/**
* 清除缓动
*/
public clear() {
if (this._tweenObj) {
this._tweenObj.clear();
}
this._tweenList = null;
return this;
}

/**
* 开始缓动
*/
private startTween() {
if (!this._tweening) {
this._tweening = true;
this.doTween();
}
}

/**
* 执行缓动
*/
private doTween() {
let self = this;
if (!this._tweenList) return;
let param = this._tweenList[0][this._tweenIndex++];
if (param) {
if (param.type == 0) {
this._tweenObj = new TweenCore();
this._tweenObj.to(
this.target,
param.prop,
param.time,
param.ease,
() => {
param.callback && param.callback();
self.doTween();
},
param.delay
);
} else {
this._tweenObj = new TweenCore();
this._tweenObj.from(
this.target,
param.prop,
param.time,
param.ease,
() => {
param.callback && param.callback();
self.doTween();
},
param.delay
);
}
} else {
if (this._loop) {
this._tweenIndex = 0;
if (this._limit[0] == -1) {
this.doTween();
} else {
if (this._limit[0] > 0) {
this._limit[0]--;
} else {
this._tweenList.shift();
this._limit.shift();
this._listIndex--;
if (this._tweenList.length == 0) {
this._tweenList = null;
}
}
this.doTween();
}
} else {
this._tweenList = null;
this._limit = [];
}
}
}
}

缓动核心类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
export class TweenCore {
private _target;
private _prop;
private _duration;
private _ease;
private _complete;
private _delay;
private _direction;
private _isDone;
private _time = 0;
private _def = {};
private _isDelay = false;

public to(
target: any,
props: any,
duration: number,
ease?: Function | null,
complete?,
delay?: number
) {
this._target = target;
this._prop = props;
this._duration = duration;
this._ease = ease || Laya.Ease.linearInOut;
this._complete = complete;
this._delay = delay ? delay : 0;
this._delay && (this._isDelay = true);
this._direction = 1;
this._isDone = false;
for (let key in this._prop) {
this._def[key] = this._target[key];
}
TweenUtil.getTweenClock().push(this);
return this;
}

public from(
target: any,
props: any,
duration: number,
ease?: Function | null,
complete?,
delay?: number
) {
this._target = target;
this._prop = props;
this._duration = duration;
this._ease = ease || Laya.Ease.linearInOut;
this._complete = complete;
this._delay = delay ? delay : 0;
this._delay && (this._isDelay = true);
this._direction = 0;
this._isDone = false;
for (let key in this._prop) {
this._def[key] = this._target[key];
}
TweenUtil.getTweenClock().push(this);
return this;
}

public update(dt) {
if (this._target && !this._isDone) {
//计算进度
this._time += dt;
if (this._isDelay) {
if (this._time >= this._delay) {
this._isDelay = false;
this._time = 0;
}
} else {
if (this._time > this._duration) {
this._time = this._duration;
this._isDone = true;
}
//更新
let ease = this._ease(this._time, 0, 1, this._duration);
for (let key in this._prop) {
if (key == "update") {
this._prop[key]();
} else {
this._target[key] =
this._def[key] +
(this._prop[key] - this._def[key]) *
(this._direction ? ease : 1 - ease);
}
}
//结束回调
if (this._isDone) {
this.clear();
this._complete && this._complete();
this._complete = null;
}
}
}
}

public clear() {
TweenUtil.getTweenClock().sub(this);
this._target = null;
this._prop = null;
this._duration = null;
this._ease = null;
this._delay = null;
this._direction = null;
this._isDone = null;
this._time = 0;
this._def = {};
this._isDelay = false;
}

public getDone() {
return this._isDone;
}
}

缓动时钟类

此处挂载到 Laya 上,也可以自定义更新逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
export class TweenClock extends Laya.Script3D {
private _tweens: TweenCore[] = [];

onAwake() {
console.log("TweenClock启动");
}

public push(tween) {
this._tweens.push(tween);
}

public sub(tween) {
let index = this._tweens.indexOf(tween);
index != -1 && this._tweens.splice(index, 1);
}

public onUpdate() {
let time = Laya.timer.delta;
let tween: TweenCore;
for (let i = this._tweens.length - 1; i >= 0; i--) {
tween = this._tweens[i];
if (tween) {
if (tween.getDone()) {
this._tweens.splice(i, 1);
continue;
}
tween.update(time);
}
}
}
}

Laya 缓动函数参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
class Ease {
static linearNone(t, b, c, d) {
return (c * t) / d + b;
}
static linearIn(t, b, c, d) {
return (c * t) / d + b;
}
static linearInOut(t, b, c, d) {
return (c * t) / d + b;
}
static linearOut(t, b, c, d) {
return (c * t) / d + b;
}
static bounceIn(t, b, c, d) {
return c - Ease.bounceOut(d - t, 0, c, d) + b;
}
static bounceInOut(t, b, c, d) {
if (t < d * 0.5) return Ease.bounceIn(t * 2, 0, c, d) * 0.5 + b;
else return Ease.bounceOut(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
}
static bounceOut(t, b, c, d) {
if ((t /= d) < 1 / 2.75) return c * (7.5625 * t * t) + b;
else if (t < 2 / 2.75)
return c * (7.5625 * (t -= 1.5 / 2.75) * t + 0.75) + b;
else if (t < 2.5 / 2.75)
return c * (7.5625 * (t -= 2.25 / 2.75) * t + 0.9375) + b;
else return c * (7.5625 * (t -= 2.625 / 2.75) * t + 0.984375) + b;
}
static backIn(t, b, c, d, s = 1.70158) {
return c * (t /= d) * t * ((s + 1) * t - s) + b;
}
static backInOut(t, b, c, d, s = 1.70158) {
if ((t /= d * 0.5) < 1)
return c * 0.5 * (t * t * (((s *= 1.525) + 1) * t - s)) + b;
return (c / 2) * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2) + b;
}
static backOut(t, b, c, d, s = 1.70158) {
return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
}
static elasticIn(t, b, c, d, a = 0, p = 0) {
var s;
if (t == 0) return b;
if ((t /= d) == 1) return b + c;
if (!p) p = d * 0.3;
if (!a || (c > 0 && a < c) || (c < 0 && a < -c)) {
a = c;
s = p / 4;
} else s = (p / Ease.PI2) * Math.asin(c / a);
return (
-(
a *
Math.pow(2, 10 * (t -= 1)) *
Math.sin(((t * d - s) * Ease.PI2) / p)
) + b
);
}
static elasticInOut(t, b, c, d, a = 0, p = 0) {
var s;
if (t == 0) return b;
if ((t /= d * 0.5) == 2) return b + c;
if (!p) p = d * (0.3 * 1.5);
if (!a || (c > 0 && a < c) || (c < 0 && a < -c)) {
a = c;
s = p / 4;
} else s = (p / Ease.PI2) * Math.asin(c / a);
if (t < 1)
return (
-0.5 *
(a *
Math.pow(2, 10 * (t -= 1)) *
Math.sin(((t * d - s) * Ease.PI2) / p)) +
b
);
return (
a *
Math.pow(2, -10 * (t -= 1)) *
Math.sin(((t * d - s) * Ease.PI2) / p) *
0.5 +
c +
b
);
}
static elasticOut(t, b, c, d, a = 0, p = 0) {
var s;
if (t == 0) return b;
if ((t /= d) == 1) return b + c;
if (!p) p = d * 0.3;
if (!a || (c > 0 && a < c) || (c < 0 && a < -c)) {
a = c;
s = p / 4;
} else s = (p / Ease.PI2) * Math.asin(c / a);
return (
a * Math.pow(2, -10 * t) * Math.sin(((t * d - s) * Ease.PI2) / p) + c + b
);
}
static strongIn(t, b, c, d) {
return c * (t /= d) * t * t * t * t + b;
}
static strongInOut(t, b, c, d) {
if ((t /= d * 0.5) < 1) return c * 0.5 * t * t * t * t * t + b;
return c * 0.5 * ((t -= 2) * t * t * t * t + 2) + b;
}
static strongOut(t, b, c, d) {
return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
}
static sineInOut(t, b, c, d) {
return -c * 0.5 * (Math.cos((Math.PI * t) / d) - 1) + b;
}
static sineIn(t, b, c, d) {
return -c * Math.cos((t / d) * Ease.HALF_PI) + c + b;
}
static sineOut(t, b, c, d) {
return c * Math.sin((t / d) * Ease.HALF_PI) + b;
}
static quintIn(t, b, c, d) {
return c * (t /= d) * t * t * t * t + b;
}
static quintInOut(t, b, c, d) {
if ((t /= d * 0.5) < 1) return c * 0.5 * t * t * t * t * t + b;
return c * 0.5 * ((t -= 2) * t * t * t * t + 2) + b;
}
static quintOut(t, b, c, d) {
return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
}
static quartIn(t, b, c, d) {
return c * (t /= d) * t * t * t + b;
}
static quartInOut(t, b, c, d) {
if ((t /= d * 0.5) < 1) return c * 0.5 * t * t * t * t + b;
return -c * 0.5 * ((t -= 2) * t * t * t - 2) + b;
}
static quartOut(t, b, c, d) {
return -c * ((t = t / d - 1) * t * t * t - 1) + b;
}
static cubicIn(t, b, c, d) {
return c * (t /= d) * t * t + b;
}
static cubicInOut(t, b, c, d) {
if ((t /= d * 0.5) < 1) return c * 0.5 * t * t * t + b;
return c * 0.5 * ((t -= 2) * t * t + 2) + b;
}
static cubicOut(t, b, c, d) {
return c * ((t = t / d - 1) * t * t + 1) + b;
}
static quadIn(t, b, c, d) {
return c * (t /= d) * t + b;
}
static quadInOut(t, b, c, d) {
if ((t /= d * 0.5) < 1) return c * 0.5 * t * t + b;
return -c * 0.5 * (--t * (t - 2) - 1) + b;
}
static quadOut(t, b, c, d) {
return -c * (t /= d) * (t - 2) + b;
}
static expoIn(t, b, c, d) {
return t == 0 ? b : c * Math.pow(2, 10 * (t / d - 1)) + b - c * 0.001;
}
static expoInOut(t, b, c, d) {
if (t == 0) return b;
if (t == d) return b + c;
if ((t /= d * 0.5) < 1) return c * 0.5 * Math.pow(2, 10 * (t - 1)) + b;
return c * 0.5 * (-Math.pow(2, -10 * --t) + 2) + b;
}
static expoOut(t, b, c, d) {
return t == d ? b + c : c * (-Math.pow(2, (-10 * t) / d) + 1) + b;
}
static circIn(t, b, c, d) {
return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
}
static circInOut(t, b, c, d) {
if ((t /= d * 0.5) < 1) return -c * 0.5 * (Math.sqrt(1 - t * t) - 1) + b;
return c * 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
}
static circOut(t, b, c, d) {
return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
}
}
Ease.HALF_PI = Math.PI * 0.5;
Ease.PI2 = Math.PI * 2;

评论