Продолжительность кинетической прокрутки (импульс) в зависимости от скорости? - PullRequest
1 голос
/ 24 ноября 2010

Я пытаюсь реализовать кинетическую прокрутку объекта списка, но у меня возникла проблема с определением величины трения (длительности) для применения на основе скорости.

my applyFriction () метод равномерно уменьшает скорость прокручиваемого объекта на основе свойства длительности.однако использование одной и той же продолжительности (например, 1 секунда) для каждого движения не кажется естественным.

для движений с небольшой скоростью (например, 5–10 пикселей) длительность в 1 секунду выглядит нормально,но применяя трение в течение 1 секунды для движений с большой скоростью (IE: 100+ пикселей), объект прокрутки будет казаться медленным и останавливаться намного быстрее.

по сути, я пытаюсь определить подходящую продолжительностьдля каждого движения, так что как малые, так и большие величины скорости будут иметь одинаковое трение, так что движущийся объект всегда будет иметь постоянный «вес».

Существует ли общий алгоритм для определения продолжительности кинетикидвижение, основанное на различных скоростях?


примечание: я программирую в ActionScript 3.0 и использую класс Tween для уменьшения скорости движущегося объекта в течение продолжительности.

Ответы [ 2 ]

6 голосов
/ 24 ноября 2010

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

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), где тау является характеристикой системы. Время затухания от произвольной скорости до заданного предела пропорционально ln (v_init) в такой системе.)

4 голосов
/ 03 июля 2013

Я уже рассматривал эту проблему раньше: почему прокрутка импульса в 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);

Фактически, именно так замедление реализовано в собственной библиотеке Apple PastryKit (а теперь часть iAd ).Снижает скорость прокрутки в 0.95 для каждого такта анимации (16,7 мс, нацелен на 60 кадров в секунду).Это соответствует постоянной времени 325 мсек.Если вы математик, то, очевидно, понимаете, что экспоненциальный характер скорости прокрутки приведет к экспоненциальному затуханию в позиции.С небольшой надписью, в конце концов вы обнаружите, что

325 = -16.7 / ln(0.95)

Давать движение:

enter image description here


Ваш вопрос был о длительность для использования.Мне нравится, как чувствует себя iPhone (в отличие от Android).я думаю, что вы должны использовать 1950 мс :

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