添加补间,以便在从快速 UI 事件触发时按顺序完成



我有一个三.js的应用程序设置,我正在尝试在两个模型之间添加一个很好的过渡。

它应该快速缩小到零,然后将下一个模型从零放大到正确的大小。

我使用的是补间.js如果 ui 事件再次快速发生,而前一个事件仍在动画中,那么它们最终会尝试一起运行并交错。

我只是希望它将其添加到队列中,因为我的补间在 oncomplete 处理程序中具有副作用。

setActiveBoxTypeByName(name) {
let rnd = Math.random();
console.log("starting setActiveBoxTypeByName", rnd);
let boxToHide = this.scene.getObjectByName(Config.activeBoxName);
let boxToDisplay = this.scene.getObjectByName(name);
let originalScaleHide = new THREE.Vector3(0, 0, 0).copy(boxToHide.scale);
let originalScaleShow = new THREE.Vector3(0, 0, 0).copy(boxToDisplay.scale);
let tweenScaleToZero = new TWEEN.Tween(boxToHide.scale)
.to({x: 0, y:0, z: 0}, 150)
.easing(TWEEN.Easing.Quadratic.In)
.onComplete(() => {
boxToHide.visible = false;
boxToHide.scale.copy(originalScaleHide);
boxToDisplay.scale.copy(new THREE.Vector3(0,0,0));
boxToDisplay.visible = true;
console.log("oncomplete setActiveBoxTypeByName", rnd);
});
let tweenScaleUpFromZero = new TWEEN.Tween(boxToDisplay.scale)
.to(originalScaleShow, 150)
.easing(TWEEN.Easing.Quadratic.InOut)
.onComplete(() => {
Config.activeBoxName = name;
console.log("oncomplete setActiveBoxTypeByName", rnd);
});
tweenScaleToZero.chain(tweenScaleUpFromZero).start();
}

问题是它附加到单选按钮列表,如果我在两者之间快速翻转,那么它就会变得一团糟。

这是因为两组单独的补间最终可能会同时播放。我在那里放了一些console.log()来证明这是正在发生的事情:

starting setActiveBoxTypeByName 0.8409190378614766
oncomplete setActiveBoxTypeByName 0.8409190378614766
oncomplete setActiveBoxTypeByName 0.8409190378614766
starting setActiveBoxTypeByName 0.5498841071087592
oncomplete setActiveBoxTypeByName 0.5498841071087592
starting setActiveBoxTypeByName 0.16717439330596795 // here
oncomplete setActiveBoxTypeByName 0.5498841071087592 // here
oncomplete setActiveBoxTypeByName 0.16717439330596795
oncomplete setActiveBoxTypeByName 0.16717439330596795

我想不出一种没有副作用的编写方法,因为它需要执行动画然后将 visible 设置为 false,而且我看不到添加到现有队列的方法。

我缺少什么技巧吗?

首先,我使用 TweenLite,但我认为您在 Tween 中有相同的方法。

我认为你可以数一数你点击收音机的次数,来计算你必须做多少个动画。然后,您可以检查第一个动画是否仍在进行中,第二个动画必须以第一个动画的"oncomplete"方法启动。

下面是一个示例:

var iterations = 0;
var tweenScaleToZero, tweenScaleUpFromZero;
$('#yourRadioButton').click( function() { iterations++; }
setActiveBoxTypeByName(name) {
let rnd = Math.random();
console.log("starting setActiveBoxTypeByName", rnd);
let boxToHide = this.scene.getObjectByName(Config.activeBoxName);
let boxToDisplay = this.scene.getObjectByName(name);
let originalScaleHide = new THREE.Vector3(0, 0, 0).copy(boxToHide.scale);
let originalScaleShow = new THREE.Vector3(0, 0, 0).copy(boxToDisplay.scale);
if( ( !tweenScaleToZero.isActive() || tweenScaleToZero === undefined ) && 
( !tweenScaleUpFromZero.isActive() || tweenScaleUpFromZero === undefined) ) { 
tweenScaleToZero = new TWEEN.Tween(boxToHide.scale) 
.to({x: 0, y:0, z: 0}, 150)
.easing(TWEEN.Easing.Quadratic.In)
.onComplete(() => {
boxToHide.visible = false;
boxToHide.scale.copy(originalScaleHide);
boxToDisplay.scale.copy(new THREE.Vector3(0,0,0));
boxToDisplay.visible = true;
console.log("oncomplete setActiveBoxTypeByName", rnd);
tweenScaleUpFromZero = new TWEEN.Tween(boxToDisplay.scale)
.to(originalScaleShow, 150)
.easing(TWEEN.Easing.Quadratic.InOut)
.onComplete(() => {
Config.activeBoxName = name;
console.log("oncomplete setActiveBoxTypeByName", rnd);
});
}).start();
if( iterations > 0 ) iterations--;
} else console.log( "Boxes are already animating." );
}

最新更新