基于速度的动力学滚动(动量)持续时间?

发布于 2024-10-04 14:34:50 字数 424 浏览 2 评论 0原文

我正在尝试实现列表对象的动态滚动,但在根据速度确定要应用的摩擦量(持续时间)时遇到问题。

我的 applyFriction() 方法根据持续时间属性均匀地降低滚动对象的速度。然而,对每个动作使用相同的持续时间(即:1 秒)看起来并不自然。

对于速度较小的运动(即:5 - 10 像素),1 秒的持续时间看起来不错,但对于速度较大的运动(即:100+ 像素),在 1 秒的持续时间内施加摩擦力,滚动对象将显得慢且停止得更快。

本质上,我试图确定每个运动的适当持续时间,以便小速度和大速度都将共享匹配的摩擦力,因此移动的物体似乎始终具有恒定的“重量”。

是否有一个通用算法来确定基于不同速度的运动持续时间?


注意:我正在使用 ActionScript 3.0 进行编程,并使用 Tween 类来降低移动对象在一段时间内的速度。

i'm trying to implement kinetic scrolling of a list object, but i'm having a problem determining the amount of friction (duration) to apply based on the velocity.

my applyFriction() method evenly reduces the velocity of the scrolling object based on a duration property. however, using the same duration (IE: 1 second) for every motion doesn't appear natural.

for motions with a small amount of velocity (IE: 5 - 10 pixels) a 1 second duration appears fine, but applying friction over a 1 second duration for motions with lots of velocity (IE: 100+ pixels) the scrolling object will appear to slow and stop much faster.

essentially, i'm trying to determine the appropriate duration for each motion so that both small and large amounts of velocity will share a matching friction, so the moving object will appear to always have a constant "weight".

is there a general algorithm for determining the duration of kinetic movement based on different velocities?


note: i'm programming in ActionScript 3.0 and employing the Tween class to reduce the velocity of a moving object over a duration.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

沧桑㈠ 2024-10-11 14:34:50

我之前研究过这个问题:为什么 Android 动量滚动感觉不如 iPhone 好?

幸运的是,一个人已经有了拿出摄像机,记录 iPhone 滚动,并弄清楚它的作用存档

轻弹列表及其动量滚动和减速

<小时>

当我开始[做这件事]时,我没有仔细注意 iPhone 上滚动的工作方式。我只是假设减速度是基于牛顿运动定律,即移动身体受到摩擦,一段时间后被迫停止。一段时间后,我意识到这实际上不是 iPhone(以及后来的 iOS 设备,例如 iPad)的做法。使用相机并捕获各种 iOS 应用程序的几十个滚动运动,我发现所有滚动都会在相同的时间后停止,无论列表的大小或轻弹的速度如何。您滑动的速度(决定滚动的初始速度)仅决定列表将停止的位置,而不是何时

这使他得到了大大简化的数学:

amplitude = initialVelocity * scaleFactor;
step = 0;

ticker = setInterval(function() {
    var delta = amplitude / timeConstant;
    position += delta;
    amplitude -= delta;
    step += 1;
    if (step > 6 * timeConstant) {
        clearInterval(ticker);
    }
}, updateInterval);

事实上,这就是苹果自己的减速的实现方式 PastryKit 库(现在是iAd 的一部分)。对于每个动画刻度,它会将滚动速度降低 0.95 倍(16.7 毫秒,目标为 60 fps)。这对应于 325 毫秒的时间常数。如果您是一名数学极客,那么显然您会意识到滚动速度的指数性质会产生位置的指数衰减。经过一些潦草的书写,最终你会发现

325 = -16.7ms / ln(0.95)

给出动议:

在此处输入图像描述


您的问题是关于 <强>使用时间。我喜欢 iPhone 的感觉(而不是 Android)。我认为你应该使用 1,950 毫秒

- (1000 ms / 60) / ln(0.95) * 6 = 1950 ms

i had looked into this problem before: why does Android momentum scrolling not feel as nice as the iPhone?

Fortunately, a guy already got out a video camera, recorded an iPhone scrolling, and figured out what it does: archive

flick list with its momentum scrolling and deceleration


When I started to work [on this], I did not pay attention carefully to the way the scrolling works on iPhone. I was just assuming that the deceleration is based on Newton’s law of motion, i.e. a moving body receiving a friction which is forced to stop after a while. After a while, I realized that this is actually not how iPhone (and later iOS devices such as iPad) does it. Using a camera and capturing few dozens scrolling movement of various iOS applications, it came to me that all the scrolling will stop after the same amount of time, regardless the size of the list or the speed of the flick. How fast you flick (which determines the initial velocity of the scrolling) only determines where the list would stop and not when.

This lead him to the greatly simplified math:

amplitude = initialVelocity * scaleFactor;
step = 0;

ticker = setInterval(function() {
    var delta = amplitude / timeConstant;
    position += delta;
    amplitude -= delta;
    step += 1;
    if (step > 6 * timeConstant) {
        clearInterval(ticker);
    }
}, updateInterval);

In fact, this is how the deceleration is implemented in Apple’s own PastryKit library (and now part of iAd). It reduces the scrolling speed by a factor of 0.95 for each animation tick (16.7 msec, targeting 60 fps). This corresponds to a time constant of 325 msec. If you are a math geek, then obviously you realize that the exponential nature of the scroll velocity will yield the exponential decay in the position. With a little bit of scriblling, eventually you find out that

325 = -16.7ms / ln(0.95)

Giving the motion:

enter image description here


Your question was about the duration to use. i like how the iPhone feels (as opposed to Android). i think you should use 1,950 ms:

- (1000 ms / 60) / ln(0.95) * 6 = 1950 ms
再可℃爱ぅ一点好了 2024-10-11 14:34:50

更好的摩擦模型是摩擦力与速度成正比。您需要一个常数来确定力和加速度(质量,或多或少)之间的关系。将这些关系写成差分方程,

F[n] = -gamma * v[n-1]
a[n] = F[n]/m
v[n] = v[n-1] + dt * a[n]
     = v[n-1] + dt * F[n] / m
     = v[n-1] - dt * gamma * v[n-1] / m
     = v[n-1] * (1 - dt*gamma/m)

因此,如果您希望减速看起来平滑且自然,您需要选择一些略小于 1 的常数,并重复将速度乘以该常数,而不是线性降低速度。当然,这只会渐近地接近零,因此您可能需要一个阈值,低于该阈值时只需将速度设置为零。

例如:

v_epsilon = <some minimum velocity>;
k_frict = 0.9; // play around with this a bit

while (v > v_epsilon) {
    v = v * k_frict;
    usleep(1000);
}

v = 0;

我想你会发现这看起来更自然。

如果您想通过线性减速来近似这一点,那么您需要使减速所花费的时间与初始速度的自然对数成正比。这看起来不太正确,但它看起来会比你现在得到的要好一些。

(为什么是自然对数?因为摩擦力与速度成正比,建立了一个一阶微分方程,它给出了 exp(-t/tau) 类型的响应,其中 tau 是系统的一个特征。从任意值衰减的时间在这样的系统中,达到给定极限的速度与 ln(v_init) 成正比。)

A better model for friction is that the frictional force is proportional to velocity. You'll need a constant to determine the relationship between force and acceleration (mass, more or less). Writing the relationships as a difference equation,

F[n] = -gamma * v[n-1]
a[n] = F[n]/m
v[n] = v[n-1] + dt * a[n]
     = v[n-1] + dt * F[n] / m
     = v[n-1] - dt * gamma * v[n-1] / m
     = v[n-1] * (1 - dt*gamma/m)

So, if you want your deceleration to look smooth and natural, instead of linearly decreasing your velocity you want to pick some constant slightly less than 1 and repeatedly multiply the velocity by this constant. Of course, this only asymptotically approaches zero, so you probably want to have a threshold below which you just set velocity to zero.

So, for example:

v_epsilon = <some minimum velocity>;
k_frict = 0.9; // play around with this a bit

while (v > v_epsilon) {
    v = v * k_frict;
    usleep(1000);
}

v = 0;

I think you'll find this looks much more natural.

If you want to approximate this with a linear speed reduction, then you'll want to make the amount of time you spend slowing down proportional to the natural log of the initial velocity. This won't look quite right, but it'll look somewhat better than what you've got now.

(Why natural log? Because frictional force proportional to velocity sets up a first-order differential equation, which gives an exp(-t/tau) kind of response, where tau is a characteristic of the system. The time to decay from an arbitrary velocity to a given limit is proportional to ln(v_init) in a system like this.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文