新的缓动模块代码已经提交到:
https://github.com/dumganhar/cocos-tween-tests
试用方式
- 克隆或者下载此仓库
- 将
assets/tween
目录拷贝到你的项目中 - 将项目中原有的
tween
/Tween
从 cc 的导入,改为从当前 ./tween/ 目录导入
支持特性
- 添加 Tween.reverse 接口,用于翻转某个动作或者翻转整个缓动
- 添加 id(id_num) 接口,用于标识动作,可用于 reverse(id) 或者 reverse(tween, id) 来翻转当前缓动或者某个缓动内的动作
- 添加 union(fromId) 接口,用于将从某个 id 开始的动作到当前动作级联成一个动作。
- Tween 中使用 sequence/parallel/then 级联子 Tween 的时候,子 Tween 允许使用不同 target 。即:解决之前 node transform 与 color / opacity 需要分别 start 的问题
- 添加 Tween.timeScale 接口,用于缩放缓动
- 添加 Tween.pause/resume/pauseAllByTarget/resumeAllByTarget 接口,用于暂停、恢复缓动
- 添加 Tween.update 接口,用于自定义缓动流程(不依赖于 target 的 start, end)
- 添加 Tween.start(time) 接口,用于从缓动的某个时间节点开始播放
- 添加 Tween.duration getter,用于获取当前缓动总时长
历史讨论
特别感谢 @SmallMain 参与设计与讨论。
后续改进(可能会在 3.8.5 中)
- @SmallMain 关于任意类型和 string 类型的缓动提案 ( issue ) ,思路很好,也不破坏兼容性 (已实现)PR
- 添加 .running getter 、 Tween.getRunningCount() 静态方法,running 用于判断当前缓动是否正在运行中,getRunningCount 静态方法用于获取当前目标对象关联的所有的缓动实例的个数 (已实现)PR
- 支持 Tween.from/fromTo 接口 ( issue ) , from 用于指定缓动的起始值,其创建的动作会从起始值缓动到当前值。fromTo 则直接同时指定起始值和结束值,不考虑当前值。
- Tween 内部 action 可能需要考虑使用对象池优化,避免频繁重复创建销毁对象,Tween 本身也需要有复位接口 ( issue )
- Tween.to 支持可变属性,比如缓动 position 属性,如果 position 持续在变化,那么 Tween.to 要最终缓动到 position 更新后的位置。
- 添加 Tween.complete/completeAll/completeByTarget 接口,用于让缓动立马完成。( issue )
- 支持 punch、shake
Updated
2024.6.13: 支持 Tween 的 pause / resume 状态自动与 Node 的 active / destroy 状态关联:PR 17141
即:
- 当 node 非激活状态时,它关联的所有 tween 实例将被暂停;
- 当 node 激活状态时,它关联的所有 tween 实例将被恢复;
- 当 node 销毁时,它关联的所有 tween 实例将被停止。
2024.6.14: 实现上述改进1
, 即支持缓动字符串类型和定制任意对象:PR 17154 ,用法如下:
- 缓动字符串
class StringTarget {
string = '';
}
用例 1(整型的字符串)
const t = new StringTarget();
t.string = '0';
// 这里 string 的值的类型可以是 number 或能转换为 number 的字符串
tween(t).to(1, { string: 100 }).start();
tween(t).to(1, { string: '100' }).start();
用例 2(浮点字符串)
const t = new StringTarget();
t.string = '10';
// 从 10 缓动到 110, 缓动过程中 t.string 的值始终保持小数点后两位有效数字
// 比如:'10.00' -> '43.33' -> '76.67' -> '110.00'
tween(t).to(1, { string: { value: 110, toFixed: 2 } }).start(); // 注意,这里使用 value 表示目标值,toFixed 表示要保留的小数位
用例3(自定义处理)
const o = {
_position: v3(0, 0, 0),
set position(v) {
this._position.set(v)
},
get position() {
return this._position;
},
gold: "¥0.00",
exp: '1000/1000',
lv: 'Lv.100',
attack: '100 points',
health: '10.00',
};
const tweenFormat = {
currency(value: number): TTweenCustomProperty<string> {
return {
value: `¥${value}`,
progress(start: number, end: number, current: string, ratio: number): string {
return `¥${lerp(start, end, ratio).toFixed(2)}`;
},
convert(v: string): number {
return Number(v.slice(1));
},
};
},
health(value: number): TTweenCustomProperty<string> {
return {
value: `${value}`,
toFixed: 2,
};
},
exp(value: number): TTweenCustomProperty<string> {
return {
value: () => `${value}/1000`,
progress(start: number, end: number, current: string, ratio: number): string {
return `${lerp(start, end, ratio).toFixed(0)}/1000`;
},
convert(v: string): number {
return Number(v.slice(0, v.indexOf('/')));
},
};
},
lv(value: number): TTweenCustomProperty<string> {
return {
value: `Lv.${value}`,
progress(start: number, end: number, current: string, ratio: number): string {
return `Lv.${lerp(start, end, ratio).toFixed(0)}`;
},
convert(v: string): number {
return Number(v.slice(v.indexOf('.') + 1));
},
};
},
};
tween(o).to(1, {
position: v3(90, 0, 0),
gold: tweenFormat.currency(100),
health: tweenFormat.health(1),
exp: tweenFormat.exp(0),
lv: tweenFormat.lv(0),
}).start();
- 定制任意对象的缓动流程
class MyObject {
angle = 0;
str = '';
private _myProp = new MyProp();
set myProp(v) {
this._myProp.x = v.x;
this._myProp.y = v.y;
}
get myProp() {
return this._myProp;
}
}
const o = new MyObject();
o.myProp.x = 1;
o.myProp.y = 1;
tween(o)
.by(1, { myProp: {
value: new MyProp(100, 100), // 目标值
progress: MyProp.lerp, // 提供自定义对象缓动过程
clone: v => v.clone(), // 提供克隆函数
add: MyProp.add, // 如果用 by 动作,则需要提供 add 方法
sub: MyProp.sub, // 如果用 by 动作,并且有 reverse 操作,则除了 add 方法,还需要提供 sub 方法
legacyProgress: false, // 设置为 false 表示启用新的基于对象参数类型的 progress 回调,旧的方式在缓动对象类型是遍历对象中值为 number 的属性然后统一回调 number 参数给 progress
} }).id(123)
.reverse(123) // 翻转
.start();
2024.6.29 添加 Tween.updateUntil API,用于不确定时间间隔的缓动,可用于追踪动态物体。
大家有任何想法也欢迎加入讨论 或者新建 issue 进行讨论。谢谢。