计算滚动惯量/动量?

Kri*_*oks 5 c user-interface scroll

如何计算滚动事件的滚动动量

我知道在结尾滚动的开头必须有两个时间戳.还必须有一个"轴变化"变量,它基本上是没有惯性滚动的量.

这是我当前负责结束滚动的代码:

if ((type == kMXTEnd || type == kMXTMovedOut) && _isScrolling)
    {
        long int finishTime = MXTimestamp();
        printf("SCEnd: Ending scroll at %ld\n",finishTime-_beginTime);

        /* scrollX is the change in X axis */
        /* finishTime is time from touch down to touch up */

        printf("  * Time: %ld ChangeX: %f\n",finishTime,scrollX);

        _isScrolling = FALSE;
        _originalScrollPoint = _scrollPoint;
    }
Run Code Online (Sandbox Code Playgroud)

是否有可能计算出" 惯性加成 "?就像惯性所获得的额外偏移量一样,除了主要滚动值之外我还可以滚动.或者我需要获得其他变量吗?

我需要这个,因为我正在编写自己的UI工具包,它实际上不是基于任何东西.

Pat*_*son 6

以下是我取得的良好效果。

在每个鼠标拖动事件(或触摸事件)上,都存储速度(因此移动量除以自上一帧以来的时间)和时间戳。您只需要最后一个,所以只有两个变量。

释放鼠标/触摸时,请检查最近的时间戳是否足够近(我使用0.3秒)。如果是这样,则将可变惯性速度设置为上一次计算出的速度;否则,将其设置为0以防止在用户仔细选择位置时滚动。

然后在每次更新时(通过计时器或每个渲染调用,具体取决于您的渲染方式),按惯性速度* INERTIA_SCROLL_FACTOR(我使用0.9)滚动,并将惯性速度乘以INERTIA_ACCELERATION(我使用0.98)。

您可能需要添加一个阈值,因此如果惯性速度变得太小,滚动将停止。我使用1作为阈值,因为我的渲染库使用浮点数作为坐标。如果坐标是整数,则其自身将降为零。

要记住的一件事是,惯性速度可以是正的也可以是负的,具体取决于方向。

因此,用伪代码:

OnMouseMove:
    inertialVelocity = moveDistance / (now - timeOfLastEvent)
    timeOfLastEvent = now

OnMouseUp:
    if (now - timeSinceLastEvent > 0.3f)
        inertialVelocity = 0

OnTimer/OnRender:
    // timeDelta is needed only when doing this on render events, just to make
    // it independent of the render speed. It is the time since the previous render
    scrollPosition += inertialVelocity * INERTIA_SCROLL_FACTOR * timeDelta
    inertialVelocity *= INERTIA_ACCELERATION * timeDelta
    // Keep in mind that velocity can be negative as well, hence the abs
    if (abs(inertialVelocity) < INERTIA_THRESHOLD)
        inertialVelocity = 0
Run Code Online (Sandbox Code Playgroud)


Bli*_*ndy 5

您可以使用"最近的轴更改"队列来模拟此情况.

如果您使用相应的时间戳存储说明最后半秒的更改,则可以测试队列是否长于某个值N(即,如果用户拖动它比平时更快).你知道最后半秒的时间,也就是你可以获得速度的时间.

将速度缩放到合理的范围(例如,对于15px/.5秒,映射到~25px/sec)并且每隔几毫秒应用负加速度(也适用于上述示例,比如说-20px/sec)(或者只要您的系统能够轻松处理它,请不要过度使用它.

然后运行一个计时器,更新每个tick(speed+=accel*time_scale)的速度,然后是position(position+=speed*time_scale).当速度达到0(或低于它)时,杀死计时器.