基本原理
概述
缓动的基本原理很简单,就是设置一个初值和终值,在每帧更新的时候根据特定的缓动函数算出对应的中间值并插值。
本工具类分为 4 个部分:缓动工具类、缓动辅助类、缓动核心类、缓动时间类。同时,本工具提供链式调用,方便进行多个缓动动作的连续执行。
缓动工具类负责管理缓动的调用,以及一个作用域所有的缓动。
缓动辅助类负责管理单个缓动的初始化,同时也是链式调用的核心类。
缓动核心类负责管理具体的缓动逻辑,所以缓动都是通过该类执行。
缓动时间类负责管理缓动的更新调用,本项目托管到 Laya 的更新脚本上。
由于本类在设计之初是在 Laya 引擎运行,因此小部分代码依托 Laya 存在,使用的时候需要根据具体项目进行修改。
使用方法
所有的操作均从缓动工具类调用,但首先在运行之前要执行 TweenUtil.start()方法来初始化整个缓动工具的更新逻辑。
to 和 from 方法表示两个不同的缓动类型,to 为从当前状态到目标状态,from 为从目标状态到当前状态。这两个方法都会返回一个 subTween 对象,我们可以以这个 subTween 对象进行链式调用,以点的方法重复调用 to、from 等方法。
例如:
1 | let obj = { x: 0 }; |
此处执行了三个缓动,obj 的 x 值从 0 到 1 到 2 再到 3。三个缓动按照顺序执行一次。
同时,本项目也提供了循环执行缓动的功能,只需要在最后调用 loop() 方法,就可以对 loop 之前的所有步骤重复执行。另外,本项目也支持设置循环次数,只需要如下调用即可:
1 | let obj = { x: 0 }; |
如果存在两个 loop,若前面的 loop 为无限循环,则后面的 loop 无法执行,若不是无限循环,则后面的 loop 会执行第一个 loop 到第二个 loop 之间的缓动行为,第一个 loop 之前的缓动行为全部舍弃。其他情况同理。
如果要清理缓动,有两种方法,一种是调用 TweenUtil.clear() 方法,传入一个缓动对象,则这个缓动对象会被清理,另一种是清理作用域上的所有缓动对象,调用 TweenUtil.clearAll() 方法,传入作用域,则该作用域上的所有缓动对象都会被清理。
特别注意,本项目目前不支持缓动对象池,因为有可能会出现引用 bug,因此需要缓动对象池的话请自行实现。
缓动工具类原理
本类内置 3 个变量 _tweenId ,_tweenDic , _tweenClock
- _tweenId 变量用于自增缓动 id,也是缓动对象字典中的唯一标识符,每个作用域对应一个缓动 id。
- _tweenDic 变量为缓动对象字典,用于存储缓动对象,结构为 { tweenId : SubTween[] } , key 为缓动 id,value 为缓动辅助类数组,保存该作用域上的所有缓动对象。
- _tweenClock 变量为缓动核心类对象,在缓动核心类中会调用它来获取缓动时间类
本类的核心方法 to 和 from 的原理相同,方法分为两个部分:
- 创建一个缓动辅助类对象,设置对象的目标并且调用对应 to/from 方法。
- 检查作用域的缓动 id,如果不存在,则初始化缓动 id,然后检查字典中是否存在对应 id 并把创建的对象保存到数组中,最后再返回这个对象。
清除缓动的原理则如下方详细代码所示。
缓动辅助类原理
本类内置 8 个变量 target , _listIndex , _tweenList , _tweening , _tweenObj , _tweenIndex , _loop , _limit
- target 变量如名字所示,就是缓动的目标对象。
- _listIndex 变量用于缓动列表的索引,主要是区别各个 loop 缓动动作组,只有调用 loop 的情况下会增加。
- _tweenList 变量用于保存缓动动作,是一个二维数组,第一维保存缓动动作组,第二维保存缓动动作序列。
- _tweening 变量用于判断当前是否正在缓动
- _tweenObj 变量保存本类当前实例化的缓动核心类对象
- _tweenIndex 变量用于缓动序列的索引
- _loop 变量用于判断是否开启循环
- _limit 变量用于保存缓动循环次数限制,是个一维数组
本类的核心方法 to 和 from 的原理相同,方法分为两个部分:
- 保存缓动参数到 _tweenList[ _listIndex ] 数组中
- 如果缓动未启动,则启动缓动
本类最关键的,就是启动缓动的逻辑,具体逻辑如下图所示
本类的启动缓动,实际上就是上一个缓动动作和下一个缓动动作的连接,具体的缓动执行和结束,还得看缓动核心类。
缓动核心类原理
本类内置 11 个变量 _target , _prop , _duration , _ease , _complete , _delay , _direction , _isDone , _time , _def , _isDelay
- _target 变量如名字所示是缓动的对象
- _prop 变量保存需要缓动的所有属性
- _duration 变量是缓动的持续时间
- _ease 变量为缓动函数,所有缓动属性都需要通过该函数进行插值
- _complete 变量为回调函数,在缓动结束后执行,主要是执行缓动辅助类中的 doTween
- _delay 变量是缓动延迟时间,在延迟时间结束后才会开始执行缓动
- _direction 变量用于区分 to 和 from
- _isDone 变量用于标记是否完成缓动
- _time 变量用于记录当前缓动执行时间
- _def 变量用于保存缓动对象的原始属性
- _isDelay 变量用于标记是否延迟执行缓动
本类的 to 和 from 方法也是初始化传入的缓动参数,并且把本类对象推到缓动时间类的遍历列表中。
本类最关键的就是缓动每一帧更新的逻辑,具体逻辑如下图所示
注意,缓动函数的传参格式为: 经过时间,起始值,结束值,总时长,返回值为 0 到 1 的之间的数值
缓动时间类原理
本类在当前示例中依托 Laya 更新,也可以自定义定时器来更新。
核心逻辑主要就是 update,遍历 _tweens ,先判断缓动核心对象是否结束缓动,结束缓动就移除,否则就执行 update 函数 ,传入 deltaTime 即 dt,单位为毫秒。
注意本类一般需要在整个项目中成为单例,不过本类并没有实现单例类,如果需要的话可自行实现。记得配合修改 TweenUtil.start 的内容。
代码
缓动工具类
1 | export default class TweenUtil { |
缓动辅助类
1 | export class SubTween { |
缓动核心类
1 | export class TweenCore { |
缓动时钟类
此处挂载到 Laya 上,也可以自定义更新逻辑
1 | export class TweenClock extends Laya.Script3D { |
Laya 缓动函数参考
1 | class Ease { |