Расчет инерции / импульса прокрутки? - PullRequest
4 голосов
/ 29 апреля 2011

Как рассчитать импульс прокрутки для события прокрутки?

Я понимаю, что в начале прокрутки в конце должно быть две отметки времени. Также должна быть переменная «изменение оси», которая в основном представляет собой сумму, по которой нужно прокручиваться без инерции.

Это мой текущий код, отвечающий за завершение прокрутки:

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;
    }

Можно ли рассчитать " сложение инерции " для этого? Как дополнительное смещение, полученное по инерции, которое я могу прокрутить в дополнение к первичному значению прокрутки. Или мне нужно получить дополнительные переменные?

Мне это нужно, потому что я пишу свой собственный инструментарий пользовательского интерфейса, который на самом деле ни на чем не основан.

Ответы [ 2 ]

5 голосов
/ 18 июня 2014

То, что я сделал с хорошими результатами, таково:

При каждом событии перетаскивания мыши (или событии касания) вы сохраняете скорость (то есть количество движения, деленное на время с последнего кадра).) и метка времени.Вам нужна только последняя, ​​так что это всего две переменные.

Когда отпущено нажатие мыши, проверьте, достаточно ли последняя временная метка (я использую 0,3 секунды).Если это так, установите переменную inertialVelocity в последнюю вычисленную скорость;в противном случае установите значение 0, чтобы предотвратить прокрутку, если пользователь тщательно выбрал позицию.

Затем при каждом обновлении (либо по таймеру, либо при каждом вызове рендеринга, в зависимости от способа рендеринга) прокручивайте по inertialVelocity *INERTIA_SCROLL_FACTOR (я использую 0,9) и умножаем инерциальную скорость на INERTIA_ACCELERATION (я использую 0,98).

Возможно, вы захотите добавить порог, поэтому прокрутка останавливается, если inertialVelocity становится слишком малой.Я использую 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
5 голосов
/ 29 апреля 2011

Вы можете смоделировать это с помощью очереди «недавние изменения оси».

Если вы сохраняете, скажем, последние полсекунды изменений с соответствующими временными метками, вы можете проверить, превышает ли очередь значение N (т. Е. Если пользователь перетянул ее быстрее, чем обычно, в конец). Вы знаете общее расстояние, пройденное за последние полсекунды, время, из которого вы можете набрать скорость.

Масштабируйте скорость до чего-то разумного (скажем .. для 15px / .5сек, сопоставьте с ~ 25px / sec) и применяйте отрицательное ускорение (также подходяще масштабируемое, например, для примера выше, скажем -20px / sec) каждую пару миллисекунды (или так быстро, как ваша система может легко справиться с этим, не перенапрягайте это).

Затем запустите таймер, обновляя скорость на каждом тике (speed+=accel*time_scale), затем позицию (position+=speed*time_scale). Когда скорость достигнет 0 (или опустится ниже ее), убейте таймер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...