正文
tween.js 英文使用指南
首先来看个例子:
hello,tween.js
tween是什么?如何使用?你为什么想用它?
补间(动画)(来自
in-between
)是一个概念,允许你以平滑的方式更改对象的属性。你只需告诉它哪些属性要更改,当补间结束运行时它们应该具有哪些最终值,以及这需要多长时间,补间引擎将负责计算从起始点到结束点的值。
例如,
position
对象拥有
x
和
y
两个坐标:
var position = { x: 100, y: 0 }
如果你想将
x
坐标的值从
100
变成
200
,你应该这么做:
// 首先为位置创建一个补间(tween)
var tween = new TWEEN.Tween(position);
// 然后告诉 tween 我们想要在1000毫秒内以动画的形式移动 x 的位置
tween.to({ x: 200 }, 1000);
一般来说这样还不够,tween 已经被创建了,但是它还没被激活(使用),你需要这样启动:
// 启动
tween.start();
最后,想要成功的完成这种效果,你需要在主函数中调用
TWEEN.update
,如下使用:
animate();
function animate() {
requestAnimationFrame(animate);
// [...]
TWEEN.update();
// [...]
}
这样在更新每帧的时候都会运行补间动画;经过 1秒后 (1000 毫秒)
position.x
将会变成
200
。
除非你在控制台中打印出
x
的值,不然你看不到它的变化。你可能想要使用
onUpdate
回调:
tween.onUpdate(function(object) {
console.log(object.x);
});
tips:你可能在这里获取不到
object.x
,具体的见我提的这个
issue
这个函数将会在动画每次更新的时候被调用;这种情况发生的频率取决于很多因素 - 例如,计算机或设备的速度有多快(以及如何繁忙)。
到目前为止,我们只使用补间动画向控制台输出值,但是您可以将它与 three.js 对象结合:
var tween = new TWEEN.Tween(cube.position)
.to({ x: 100, y: 100, z: 100 }, 10000)
.start();
animate();
function animate() {
requestAnimationFrame(animate);
TWEEN.update();
threeRenderer.render(scene, camera);
}
在这种情况下,因为three.js渲染器将在渲染之前查看对象的位置,所以不需要使用明确的
onUpdate
回调。
你可能也注意到了一些不同的地方:tween.js 可以链式调用! 每个
tween
函数都会返回
tween
实例,所以你可以重写下面的代码:
var tween = new TWEEN.Tween(position);
tween.to({ x: 200 }, 1000);
tween.start();
改成这样:
var tween = new TWEEN.Tween(position)
.to({ x: 200 }, 1000)
.start();
在将会看到很多例子,所以熟悉它是很好的!比如
04-simplest
这个例子。
tween.js的动画
Tween.js 不会自行运行。你需要显式的调用
update
方法来告诉它何时运行。推荐的方法是在主动画循环中执行这个操作。使用
requestAnimationFrame
调用此循环以获得最佳的图形性能。
比如之前这个例子:
animate();
function animate() {
requestAnimationFrame(animate);
// [...]
TWEEN.update();
// [...]
}
如果调用的时候不传入参数,
update
将会判断当前时间点以确定自上次运行以来已经有多久。
当然你也可以传递一个明确的时间参数给
update
TWEEN.update(100);
意思是"更新时间 = 100 毫秒"。你可以使用它来确保代码中的所有时间相关函数都使用相同的时间值。例如,假设你有一个播放器,并希望同步运行补间。 你的
animate
函数可能看起来像这样:
var currentTime = player.currentTime;
TWEEN.update(currentTime);
我们使用明确的时间值进行单元测试。你可以看下
tests.js
这个例子,看看我们如何用不同的值调用
TWEEN.update()
来模拟时间传递。
控制一个补间
start 和 stop
到目前为止,我们已经了解了
Tween.start
方法,但是还有更多的方法来控制单个补间。 也许最重要的一个是
star
对应的方法:
停止
。 如果你想取消一个补间,只要调用这个方法通过一个单独的补间:
tween.stop();
停止一个从未开始或已经停止的补间没有任何效果。 没有错误被抛出。
start
方法接受一个参数
time
。如果你使用它,那么补间不会立即开始,直到特定时刻,否则会尽快启动(i.e 即在下次调用
TWEEN.update
)。
update
补间也有一个更新的方法---这实际上是由
TWEEN.update
调用的。 你通常不需要直接调用它,除非你是个 疯狂的hacker。
chain
当你顺序排列不同的补间时,事情会变得有趣,例如在上一个补间结束的时候立即启动另外一个补间。我们称这为链式补间,这使用
chain
方法去做。因此,为了使
tweenB
在
tewwnA
启动:
tweenA.chain(tweenB);
或者,对于一个无限的链式,设置tweenA一旦tweenB完成就开始:
tweenA.chain(tweenB);
tweenB.chain(tweenA);
关于无限的链式查看
Hello world
。
在其他情况下,您可能需要将多个补间链接到另一个补间,以使它们(链接的补间)同时开始动画:
tweenA.chain(tweenB,tweenC);
警告:调用
tweenA.chain(tweenB)
实际上修改了tweenA,所以tweenA总是在tweenA完成时启动。
chain
的返回值只是tweenA,不是一个新的tween。
repeat
如果你想让一个补间永远重复,你可以链接到自己,但更好的方法是使用
repeat
方法。 它接受一个参数,描述第一个补间完成后需要多少次重复
tween.repeat(10); // 循环10次
tween.repeat(Infinity); // 无限循环
补间的总次数将是重复参数加上一个初始补间。查看
Repeat
。
yoyo
这个功能只有在独自使用
repeat
时才有效果。 活跃时,补间的行为将像 yoyo 一样,i.e 它会从起始值和结束值之间跳出,而不是从头开始重复相同的顺序。
delay
更复杂的安排可能需要在实际开始运行之前延迟补间。 你可以使用
delay
方法来做到这一点
tween.delay(1000);
tween.start();
将在调用启动方法后的1秒钟后开始执行。
控制所有补间
在 TWEEN 全局对象中可以找到以下方法,除了
update
之外,通常不需要使用其中的大部分对象。
TWEEN.update(time)
我们已经讨论过这种方法。 它用于更新所有活动的补间。
如果
time
不指定,它将使用当前时间。
TWEEN.getAll and TWEEN.removeAll
用于获取对活动
tweens
数组的引用,并分别仅从一个调用中将它们全部从数组中删除
TWEEN.add(tween) and TWEEN.remove(tween)
用于将补间添加到活动补间的列表,或者分别从列表中删除特定的补间。
这些方法通常只在内部使用,但是如果您想要做一些有趣的事情,则会被暴露。
控制补间组
使用
TWEEN
单例来管理补间可能会导致包含许多组件的大型应用程序出现问题。 在这些情况下,您可能希望创建自己的更小的补间组。
示例:交叉组件冲突
如果使用
TWEEN
有多个组件,并且每个组件都想管理自己的一组补间,则可能发生冲突。 如果一个组件调用
TWEEN.update()
或
TWEEN.removeAll()
,则其他组件的补间也将被更新或删除。
创建你自己的补间组
为了解决这个问题,每个组件都可以创建自己的
TWEEN.Group
实例(这是全局的
TWEEN
对象在内部使用的)。 实例化新的补间时,可以将这些组作为第二个可选参数传入:
var groupA = new TWEEN.Group();
var groupB = new TWEEN.Group();
var tweenA = new TWEEN.Tween({ x: 1 }, groupA)
.to({ x: 10 }, 100)
.start();
var tweenB = new TWEEN.Tween({ x: 1 }, groupB)
.to({ x: 10 }, 100)
.start();
var tweenC = new TWEEN.Tween({ x: 1 })
.to({ x: 10 }, 100)
.start();
groupA.update(); // 只更新tweenA
groupB.update(); // 只更新tweenB
TWEEN.update(); // 只更新tweenC
groupA.removeAll(); // 只移除tweenA
groupB.removeAll(); // 只移除tweenB
TWEEN.removeAll(); // 只移除tweenC
通过这种方式,每个组件都可以处理创建,更新和销毁自己的一组补间。
改变缓动功能
Tween.js 将以线性方式执行值之间的插值(即缓动),所以变化将与流逝的时间成正比。 这是可以预见的,但在视觉上也是相当无趣的。 不要担心 - 使用缓动方法可以轻松更改此行为。 例如: