JavaScript Three.js/logic——如何在给定的时间内仅使用本机js将对象从一个位置切换到另一个位置

JavaScript Three.js/logic——如何在给定的时间内仅使用本机js将对象从一个位置切换到另一个位置,javascript,math,logic,tween,Javascript,Math,Logic,Tween,我基本上希望能够在精确的时间内将一个对象从开始位置移动到结束位置,例如,在750毫秒内将立方体从{x:0,y:0,z:0}移动到{x:5,y:-3,z:10}。我需要能够计算精确到毫秒的运动,以便与音频正确对齐,因此我需要能够计算从一帧到下一帧所需的时间,并将其考虑到我的等式中。我让它几乎完全正常工作,我不想粘贴我的整个项目,因为它依赖于几个文件,但我将引用到目前为止的关键计算,但请记住,下面的代码本身是不可测试的,因为它依赖于许多其他东西,但我只想分享一般方法。在我的主文件和所有助手函数中,我

我基本上希望能够在精确的时间内将一个对象从开始位置移动到结束位置,例如,在750毫秒内将立方体从{x:0,y:0,z:0}移动到{x:5,y:-3,z:10}。我需要能够计算精确到毫秒的运动,以便与音频正确对齐,因此我需要能够计算从一帧到下一帧所需的时间,并将其考虑到我的等式中。我让它几乎完全正常工作,我不想粘贴我的整个项目,因为它依赖于几个文件,但我将引用到目前为止的关键计算,但请记住,下面的代码本身是不可测试的,因为它依赖于许多其他东西,但我只想分享一般方法。在我的主文件和所有助手函数中,我在setInterval(update,1000/FPS)中设置了一个update()函数,FPS设置为60

正如您可能已经猜到的那样,这种情况并不是每秒发生60次,因为浏览器性能有时会将其速度降低几十毫秒,甚至更少,但仍然如此。所以在我的更新函数中,它是这样的(我不确定要捕获哪些变量,一帧到下一帧的文字差异,或者差异的比率,所以我现在捕获了这两个变量):

如您所见,我的三个.js对象都嵌套在一个名为“things”的包装器对象数组中,每个“things”都有一个从主更新函数调用的更新函数。稍后我们将回到这一点,但首先是另一个主辅助函数(这是问题的重点),tween函数(仍在这个通用的主辅助函数文件中):

因此,以前的函数myTween实际上是一个构造函数,在开始时,它将一个新的myTween设置为“me”对象,它引用“things”(THREE.js对象的包装器)本身。tween的“first”设置为“me.ok”,表示起始位置,“second”表示它要tween到的位置,设置为变量“me.ko”,当它到达它时(从函数“reach”调用),它将tween.first重置为旧的me.ko(也就是说,将新的开始位置更改为旧的结束位置)并将tween.second设置为新的随机生成的位置,它会不断重复并记录从一个位置到另一个位置所花费的时间。(正如您可能已经猜到的,“totalTime”是它在两个位置之间应该花费的时间量)

它几乎可以非常精确地工作,除了它通常大约16毫秒,要么太少,要么太多(大约1000/60),或者有时少几毫秒,要么多几毫秒。这是一个问题,因为我需要精确到毫秒

如果上面的所有代码都太复杂而无法获得,那么整个代码的关键部分是:

stepAmount = (
                    ((curDist) /   
                        (
                            this.totalTime * (
                                1
                            )
                        )) * diff
                        *deltaTween * deltaTime
                        /*
                        (
                            (originalTotalTime - this.totalTime) /
                            (this.totalTime)
                        )*/
                )
要正确计算二者之间每帧的正确步长


不用说,我对使用tween.js等库不感兴趣。

大多数tween引擎不使用步进量,也不保持任何状态(或不太多状态)。它们只有开始时间和持续时间(或结束时间和计算持续时间)

首先将其转换为一个标准化(0到1)的数字

然后用一个

然后可以计算tweened值

value = startValue + (endValue - startValue) * t
不需要状态。对于给定的
time
值,您将始终得到相同的结果

这使您可以“拖动”时间以显示动画的任何状态

然后,他们可以选择如何在持续时间前后处理
t

  • 让我们继续吧

  • 原地回环

    t = t % 1
    
  • 到头来

    t = max(min(t, 1), 0)
    
  • 乒乓球

    t = (t % 2) < 1 ? t : 2 - t;
    
    canvas{边框:1px纯黑}

    @gman在解释这是如何工作的方面做得很好

    我想提供一个使用“基于步骤”的tween的解决方案

    class-Tween{
    构造函数({from,to,change,steps,easeFn,duration,cb}){
    this.from=from
    this.to=typeof to==“未定义”?from+change:to
    this.change=typeof change==“未定义”?to-from:change
    this.steps=步骤
    此步骤=0
    this.duration=持续时间
    this.easeFn=easeFn的类型!=“函数”?t=>t:easeFn
    this.cb=typeof cb=='undefined'?()=>{}:cb
    this.update=this.update.bind(this)
    }
    勾选(){this.stepthis.endTime)返回此.stop()
    this.requestId=window.requestAnimationFrame(this.update)
    if(this.step<(现在/这个.endTime)*this.steps | 0){
    这个。勾选()
    this.cb(this.value)
    }
    }
    开始(){
    this.startTime=window.performance.now()
    this.endTime=this.startTime+this.duration
    this.requestId=window.requestAnimationFrame(this.update)
    }
    获取值(){
    返回this.from+(this.to-this.from)*this.easeFn(this.step/this.steps)
    }
    停止(){if(this.requestId)window.cancelAnimationFrame(this.requestId)}
    }
    
    我构建了它,以便您可以使用和绝对结束值,或者从属性更改
    的值

    cb
    属性是更新时使用tween值调用的属性

    我甚至还加入了一个可选的
    easeFn
    属性,这样您就可以简化值,同时仍然允许这个tween类的阶跃性质

    //示例一(使用'from'和'to')
    const exampleOne=新吐温({
    从:-10,
    至:0,,
    步骤:5,
    持续时间:1000,
    cb:v=>console.log(v)
    }).start()
    //示例二(使用'from'和'change')
    
    t = easingFunc(t)
    
    value = startValue + (endValue - startValue) * t
    
    t = t % 1
    
    t = max(min(t, 1), 0)
    
    t = (t % 2) < 1 ? t : 2 - t;